typecheck: diagnose missing method names
This commit is contained in:
+1
-1
@@ -627,7 +627,7 @@ static TypeFieldCheck *collect_class_field_type_checks(FILE *f){
|
||||
static TypeMethodCheck *collect_class_method_type_checks(FILE *f){ TypeMethodCheck *checks=NULL; char line[4096]; char current_class[128]=""; while(fgets(line,sizeof(line),f)){ char tmp[4096],up[64],w[128]; char *t; strncpy(tmp,line,sizeof(tmp)-1); tmp[sizeof(tmp)-1]=0; t=trim_inplace(tmp); if(is_blank_or_comment(t)) continue; first_word(t,w,sizeof(w)); upper_copy(up,w,sizeof(up)); if(!strcmp(up,"CLASS")){ const char *pcur=t+5; char *cls=unquote_token(&pcur); snprintf(current_class,sizeof(current_class),"%s",trim_inplace(cls)); free(cls); continue; } if((!strcmp(up,"END")||!strcmp(up,"ENDCLASS"))&¤t_class[0]){ current_class[0]=0; continue; } if(current_class[0]&&!strcmp(up,"TEACH")){ char teachline[4096]; char *fname=NULL; char **params=NULL; int pcnt=0; strncpy(teachline,t,sizeof(teachline)-1); teachline[sizeof(teachline)-1]=0; parse_teach_parts(teachline,&fname,¶ms,&pcnt); add_type_method_check(&checks,current_class,trim_inplace(fname)); while(fgets(line,sizeof(line),f)){ char inner[4096],iup[64],iw[128]; char *it; strncpy(inner,line,sizeof(inner)-1); inner[sizeof(inner)-1]=0; it=trim_inplace(inner); if(is_blank_or_comment(it)) continue; first_word(it,iw,sizeof(iw)); upper_copy(iup,iw,sizeof(iup)); if(!strcmp(iup,"END")||!strcmp(iup,"LEARNED")) break; } } } rewind(f); return checks; }
|
||||
static int typecheck_file(const char *path){ FILE *f=fopen(path,"rb"); char line[4096]; int line_no=0,errs=0; Var *types=NULL; TypeParamCheck *param_checks=NULL; TypeFieldCheck *field_checks=NULL; TypeMethodCheck *method_checks=NULL; TypeArityCheck *arity_checks=NULL; TypeReturnCheck *return_checks=NULL; char current_func[256]=""; char current_method[256]=""; char current_class[128]=""; char declared_classes[128][256]; char declared_functions[128][256]; char declared_methods[128][256]; char declared_fields[128][256]; char declared_objects[128][256]; int declared_class_count=0,declared_function_count=0,declared_method_count=0,declared_field_count=0,declared_object_count=0; int in_teach=0,return_seen=0,top_level_return_seen=0,nested_blocks=0,conditional_paths_complete=1; int branch_returned[64],branch_has_else[64]; if(!f){ fprintf(stderr,"Could not open %s\n",path); return 1; } param_checks=collect_function_param_type_checks(f); arity_checks=collect_function_arity_checks(f); return_checks=collect_function_return_type_checks(f); field_checks=collect_class_field_type_checks(f); method_checks=collect_class_method_type_checks(f); type_env_set(&types,"RESULT","ANY"); type_env_set(&types,"LASTERROR","TEXT"); type_env_set(&types,"LASTERRORFILE","TEXT"); type_env_set(&types,"LASTERRORLINE","NUMBER"); type_env_set(&types,"LASTEXIT","NUMBER"); while(fgets(line,sizeof(line),f)){ char tmp[4096],up[64],w[128]; char *t; line_no++; strncpy(tmp,line,sizeof(tmp)-1); tmp[sizeof(tmp)-1]=0; t=trim_inplace(tmp); if(is_blank_or_comment(t)) continue; first_word(t,w,sizeof(w)); upper_copy(up,w,sizeof(up)); if(!strcmp(up,"CLASS")){ const char *pcur=t+5; char *cls=unquote_token(&pcur); char *name=trim_inplace(cls); char *extra=trim_inplace((char *)pcur); int duplicate=0,ci; for(ci=0;ci<declared_class_count;ci++) if(ci_eq(declared_classes[ci],name)){ duplicate=1; break; } if(!*name){ printf("%s:%d: CLASS needs a class name. Add a name after CLASS, such as CLASS Player.\n",path,line_no); errs++; current_class[0]=0; } else if(*extra){ printf("%s:%d: Class %s has extra text after its name. Keep only the class name after CLASS.\n",path,line_no,name); errs++; } else if(duplicate){ printf("%s:%d: Class %s is declared more than once. Give each class a different name.\n",path,line_no,name); errs++; } else if(declared_class_count<128) snprintf(declared_classes[declared_class_count++],sizeof(declared_classes[0]),"%s",name); snprintf(current_class,sizeof(current_class),"%s",name); declared_field_count=0; free(cls); }
|
||||
else if(current_class[0]&&!strcmp(up,"HAS")){ const char *pcur=t+3; char *field=unquote_token(&pcur); char *field_type=unquote_token(&pcur); char *name=trim_inplace(field); char *ft=trim_inplace(field_type); char *extra=trim_inplace((char *)pcur); int duplicate=0,fi; for(fi=0;fi<declared_field_count;fi++) if(ci_eq(declared_fields[fi],name)){ duplicate=1; break; } if(duplicate){ printf("%s:%d: Class %s declares field %s more than once. Give each field a different name.\n",path,line_no,current_class,name); errs++; } else if(!*ft){ printf("%s:%d: Class %s field %s is missing a type. Add a type such as NUMBER, TEXT, YESNO, LIST, or MAP after the field name.\n",path,line_no,current_class,name); errs++; } else if(!claro_is_type_word(ft)){ printf("%s:%d: Class %s field %s uses an unknown type %s. Use a Claro type such as NUMBER, TEXT, YESNO, LIST, or MAP.\n",path,line_no,current_class,name,ft); errs++; } else if(*extra){ printf("%s:%d: Class %s field %s has extra text after type %s. Keep only the field name and one type.\n",path,line_no,current_class,name,ft); errs++; } else if(declared_field_count<128) snprintf(declared_fields[declared_field_count++],sizeof(declared_fields[0]),"%s",name); free(field); free(field_type); }
|
||||
else if(!strcmp(up,"TEACH")){ char teachline[4096],full_name[256],*fname=NULL,**params=NULL; int pcnt=0; int duplicate_method=0; strncpy(teachline,t,sizeof(teachline)-1); teachline[sizeof(teachline)-1]=0; parse_teach_parts(teachline,&fname,¶ms,&pcnt); if(!fname||!*trim_inplace(fname)){ printf("%s:%d: TEACH needs a function name. Add a name after TEACH, such as TEACH greet.\n",path,line_no); errs++; } if(current_class[0]) snprintf(full_name,sizeof(full_name),"%s.%s",current_class,fname); else snprintf(full_name,sizeof(full_name),"%s",fname); if(current_class[0]){ int mi; for(mi=0;mi<declared_method_count;mi++) if(ci_eq(declared_methods[mi],full_name)){ duplicate_method=1; break; } if(duplicate_method){ printf("%s:%d: Method %s is declared more than once. Give each method a different name.\n",path,line_no,full_name); errs++; } else if(declared_method_count<128) snprintf(declared_methods[declared_method_count++],sizeof(declared_methods[0]),"%s",full_name); } else { int fi,duplicate_function=0; for(fi=0;fi<declared_function_count;fi++) if(ci_eq(declared_functions[fi],full_name)){ duplicate_function=1; break; } if(duplicate_function){ printf("%s:%d: Function %s is declared more than once. Give each function a different name.\n",path,line_no,full_name); errs++; } else if(declared_function_count<128) snprintf(declared_functions[declared_function_count++],sizeof(declared_functions[0]),"%s",full_name); } { const char *duplicate=duplicate_param_name(params,pcnt); if(duplicate){ printf("%s:%d: %s %s declares parameter %s more than once. Give each parameter a different name.\n",path,line_no,current_class[0]?"Method":"Function",full_name,trim_inplace((char *)duplicate)); errs++; } } { int pi; for(pi=0;pi<pcnt;pi++) type_env_set(&types,params[pi],"ANY"); } current_func[0]=0; current_method[0]=0; return_seen=0; top_level_return_seen=0; nested_blocks=0; conditional_paths_complete=1; in_teach=1; if(current_class[0]) snprintf(current_method,sizeof(current_method),"%s",full_name); if(current_class[0]){ TypeFieldCheck *fc; for(fc=field_checks;fc;fc=fc->next) if(ci_eq(fc->cls,current_class)) type_env_set(&types,fc->field,fc->type); } { const char *declared_return=type_return_check_for(return_checks,full_name); if(declared_return&&!claro_is_type_word(declared_return)){ printf("%s:%d: %s %s declares an unknown return type %s. Use a Claro type such as NUMBER, TEXT, YESNO, LIST, or MAP.\n",path,line_no,strchr(full_name,'.')?"Method":"Function",full_name,declared_return); errs++; } else if(declared_return) snprintf(current_func,sizeof(current_func),"%s",full_name); } }
|
||||
else if(!strcmp(up,"TEACH")){ char teachline[4096],full_name[256],*fname=NULL,**params=NULL; int pcnt=0; int duplicate_method=0; strncpy(teachline,t,sizeof(teachline)-1); teachline[sizeof(teachline)-1]=0; parse_teach_parts(teachline,&fname,¶ms,&pcnt); if(!fname||!*trim_inplace(fname)){ if(current_class[0]) printf("%s:%d: Method %s needs a method name. Add a name after TEACH, such as TEACH show.\n",path,line_no,current_class); else printf("%s:%d: TEACH needs a function name. Add a name after TEACH, such as TEACH greet.\n",path,line_no); errs++; } if(!fname) fname=xstrdup(""); if(current_class[0]) snprintf(full_name,sizeof(full_name),"%s.%s",current_class,fname); else snprintf(full_name,sizeof(full_name),"%s",fname); if(current_class[0]){ int mi; for(mi=0;mi<declared_method_count;mi++) if(ci_eq(declared_methods[mi],full_name)){ duplicate_method=1; break; } if(duplicate_method){ printf("%s:%d: Method %s is declared more than once. Give each method a different name.\n",path,line_no,full_name); errs++; } else if(declared_method_count<128) snprintf(declared_methods[declared_method_count++],sizeof(declared_methods[0]),"%s",full_name); } else { int fi,duplicate_function=0; for(fi=0;fi<declared_function_count;fi++) if(ci_eq(declared_functions[fi],full_name)){ duplicate_function=1; break; } if(duplicate_function){ printf("%s:%d: Function %s is declared more than once. Give each function a different name.\n",path,line_no,full_name); errs++; } else if(declared_function_count<128) snprintf(declared_functions[declared_function_count++],sizeof(declared_functions[0]),"%s",full_name); } { const char *duplicate=duplicate_param_name(params,pcnt); if(duplicate){ printf("%s:%d: %s %s declares parameter %s more than once. Give each parameter a different name.\n",path,line_no,current_class[0]?"Method":"Function",full_name,trim_inplace((char *)duplicate)); errs++; } } { int pi; for(pi=0;pi<pcnt;pi++) type_env_set(&types,params[pi],"ANY"); } current_func[0]=0; current_method[0]=0; return_seen=0; top_level_return_seen=0; nested_blocks=0; conditional_paths_complete=1; in_teach=1; if(current_class[0]) snprintf(current_method,sizeof(current_method),"%s",full_name); if(current_class[0]){ TypeFieldCheck *fc; for(fc=field_checks;fc;fc=fc->next) if(ci_eq(fc->cls,current_class)) type_env_set(&types,fc->field,fc->type); } { const char *declared_return=type_return_check_for(return_checks,full_name); if(declared_return&&!claro_is_type_word(declared_return)){ printf("%s:%d: %s %s declares an unknown return type %s. Use a Claro type such as NUMBER, TEXT, YESNO, LIST, or MAP.\n",path,line_no,strchr(full_name,'.')?"Method":"Function",full_name,declared_return); errs++; } else if(declared_return) snprintf(current_func,sizeof(current_func),"%s",full_name); } }
|
||||
else if(!strcmp(up,"IF")){ if(in_teach){ if(nested_blocks<64){ branch_returned[nested_blocks]=0; branch_has_else[nested_blocks]=0; } nested_blocks++; } }
|
||||
else if(!strcmp(up,"ELSE")){ if(in_teach&&nested_blocks>0&&nested_blocks<=64){ if(!branch_returned[nested_blocks-1]) conditional_paths_complete=0; branch_has_else[nested_blocks-1]=1; branch_returned[nested_blocks-1]=0; } }
|
||||
else if(!strcmp(up,"END")||!strcmp(up,"LEARNED")||!strcmp(up,"ENDIF")){ if(in_teach&&nested_blocks>0){ int nested_complete=(nested_blocks<=64&&branch_has_else[nested_blocks-1]&&branch_returned[nested_blocks-1]); if(nested_blocks<=64&&(!branch_has_else[nested_blocks-1]||!branch_returned[nested_blocks-1])) conditional_paths_complete=0; nested_blocks--; if(nested_complete&&nested_blocks>0&&nested_blocks<=64) branch_returned[nested_blocks-1]=1; } else if(in_teach){ if(current_func[0]&&!return_seen){ const char *need=type_return_check_for(return_checks,current_func); printf("%s:%d: %s %s declares RETURNS %s but has no RETURN statement. Add RETURN with a %s value.\n",path,line_no,strchr(current_func,'.')?"Method":"Function",current_func,need,need); errs++; } else if(current_func[0]&&(!top_level_return_seen&&!conditional_paths_complete)){ const char *need=type_return_check_for(return_checks,current_func); printf("%s:%d: %s %s declares RETURNS %s but does not return a %s value on every path. Add RETURN to each branch or after the conditional.\n",path,line_no,strchr(current_func,'.')?"Method":"Function",current_func,need,need); errs++; } in_teach=0; current_func[0]=0; current_method[0]=0; } else current_class[0]=0; }
|
||||
|
||||
Reference in New Issue
Block a user