typecheck: diagnose missing unchecked function args

This commit is contained in:
Hermes Agent
2026-09-02 12:00:07 +00:00
parent 3173eafb36
commit 1e3e7fd9fa
8 changed files with 25 additions and 4 deletions
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## v1.18.26-dev missing unchecked function argument diagnostic
- Added a focused negative `claro typecheck` fixture for calling a simple function without its declared argument, such as `TEACH greet name` followed by `DO greet`.
- Improved the static arity check so simple functions without `CHECK TYPE` hints still report a beginner-facing missing-argument diagnostic.
- Wired the fixture into the typecheck diagnostics validator and `claro validate`.
## v1.18.26-dev CI release validation coverage
- Added `tools/validate_ci_workflow.py` to assert that Forgejo/Gitea CI keeps running Claro's current release gates.
+1
View File
@@ -146,6 +146,7 @@ DO square "oops"
```text
Type mismatch for function square: parameter amount needs NUMBER, but this argument looks like TEXT.
Function square needs argument amount as NUMBER, but this call does not provide it.
Function greet needs 1 argument, but this call gives 0. Add the missing argument.
Function square only accepts 1 argument, but this call gives 2. Remove the extra argument.
Function squre is not known yet. Check the function name or add TEACH squre before calling it.
```
+6
View File
@@ -339,6 +339,12 @@ Both sides of this narrow field foundation are covered by validation: `tests/typ
This slice is intentionally small: it covers direct `NEW Class object` plus `SET object.field value` cases in one file. Field declarations are collected even when a learner writes a simple method before a later `HAS` field, so the type checker can still report the field's declared type. Broader object flows, aliases, method return checks, and richer object signatures remain future work.
Simple functions also get an arity check before running. If a learner defines `TEACH greet name` and then writes `DO greet` without the `name` argument, `claro typecheck` reports:
```text
Function greet needs 1 argument, but this call gives 0. Add the missing argument.
```
## Status
This is currently a static checker feature. It improves `claro typecheck` and validation confidence for `DO` and compatibility `CALL ... WITH` function calls, simple `DO object.method ...` calls where the object was created with `NEW Class name`, and direct assignments to known object fields. Runtime enforcement for every container mutation and richer function/object signatures can be added later after the syntax is classroom-tested.
+1 -1
View File
@@ -52,7 +52,7 @@ Ready now:
- typed variables such as `SET score NUMBER 10`
- `TYPE OF` and `CHECK TYPE`
- typed list/map checks through `claro typecheck`
- a narrow function/method argument check: `CHECK TYPE parameter IS TYPE` inside a function or simple object method lets `claro typecheck` accept correct checked calls, catch mismatched `DO`, `CALL ... WITH`, `DO object.method ...`, and compatibility `CALL object.method WITH ...` arguments, including checked methods that appear after another method in the same class, report missing checked function and method arguments, catch extra arguments to simple functions and checked methods even when the checked method appears after another method in the same class, catch modern `DO` and compatibility `CALL ... WITH` calls to undeclared simple functions, explain when `DO object.method ...` or compatibility `CALL object.method WITH ...` happens before the object is created with `NEW` even if the method name is also wrong, and catch simple calls to undeclared methods with a class-specific `TEACH` hint
- a narrow function/method argument check: `CHECK TYPE parameter IS TYPE` inside a function or simple object method lets `claro typecheck` accept correct checked calls, catch mismatched `DO`, `CALL ... WITH`, `DO object.method ...`, and compatibility `CALL object.method WITH ...` arguments, including checked methods that appear after another method in the same class, report missing checked function and method arguments, report missing unchecked arguments for simple functions, catch extra arguments to simple functions and checked methods even when the checked method appears after another method in the same class, catch modern `DO` and compatibility `CALL ... WITH` calls to undeclared simple functions, explain when `DO object.method ...` or compatibility `CALL object.method WITH ...` happens before the object is created with `NEW` even if the method name is also wrong, and catch simple calls to undeclared methods with a class-specific `TEACH` hint
- a narrow object-field assignment/check-type check for simple `NEW Class object` plus direct `SET object.field value` and `CHECK TYPE object.field IS TYPE` cases when the class declares `HAS field TYPE`; validation now covers correct NUMBER, TEXT, and YESNO direct assignments, direct `CHECK TYPE` metadata acceptance for NUMBER/TEXT/YESNO fields, negative NUMBER/TEXT/YESNO field `CHECK TYPE` metadata mismatches, NUMBER/TEXT/YESNO-expectation unknown-field `CHECK TYPE` diagnostics, missing-object field assignment and `CHECK TYPE` diagnostics, NUMBER/TEXT/YESNO wrong-type diagnostics, field collection when a `HAS` field appears after a simple method, NUMBER/TEXT/YESNO-valued unknown-field diagnostics for direct assignments to undeclared fields, plus a plain beginner-facing unknown-field diagnostic when the assigned expression type is not inferable yet
Still needed:
+1 -1
View File
@@ -31,7 +31,7 @@ See `CURRENT_STATUS.md` for the detailed feature matrix.
1. Keep beginner-facing docs current and separate from historical release notes.
2. Keep examples aligned with the modern simple syntax (`END`, `DO`, short `SET`, short `ASK`) while documenting older compatibility forms separately.
3. Expand validation around typecheck diagnostics and package/networking safety. Current Forgejo/Gitea CI runs the documented release gates (`claro validate`, typecheck diagnostics validation, version convention validation, and CI workflow coverage validation). Current package safety validation covers safe manifest/lockfile creation, rejecting unsafe package names during `package add`, detecting unsafe package names already present in `claro.project` during `package doctor`, refusing to write lockfile data for unsafe package names during `package lock`, and making `package remove` fail instead of reporting success when unsafe package names remain during lockfile refresh. Current function validation covers correct checked calls, wrong-type arguments, missing checked-argument diagnostics, extra-argument diagnostics, and beginner-facing unknown-function diagnostics for mistyped modern `DO` and compatibility `CALL ... WITH` calls; current object-method parameter validation covers correct modern `DO object.method ...` and compatibility `CALL object.method WITH ...` checked calls, wrong-type diagnostics for both call forms, checked methods after another method in the same class, missing and extra checked-argument diagnostics including the extra-argument case for a checked method after another method in the same class, missing-object guidance when `DO player.method ...` or compatibility `CALL object.method WITH ...` appears before `NEW` even if the method name is also wrong, and a class-specific unknown-method diagnostic when a learner calls a method the class does not declare; object-field validation covers correct NUMBER, TEXT, and YESNO direct `SET object.field value` assignments, direct `CHECK TYPE` metadata acceptance for NUMBER/TEXT/YESNO fields, negative NUMBER/TEXT/YESNO metadata mismatches, NUMBER/TEXT/YESNO-expectation unknown-field `CHECK TYPE` diagnostics, missing-object field assignment and `CHECK TYPE` diagnostics, NUMBER/TEXT/YESNO wrong-type direct assignments, field collection when `HAS` appears after a simple method, NUMBER/TEXT/YESNO-valued unknown-field direct assignments, plus a plain beginner-facing unknown-field diagnostic when the assigned expression type is not inferable yet.
3. Expand validation around typecheck diagnostics and package/networking safety. Current Forgejo/Gitea CI runs the documented release gates (`claro validate`, typecheck diagnostics validation, version convention validation, and CI workflow coverage validation). Current package safety validation covers safe manifest/lockfile creation, rejecting unsafe package names during `package add`, detecting unsafe package names already present in `claro.project` during `package doctor`, refusing to write lockfile data for unsafe package names during `package lock`, and making `package remove` fail instead of reporting success when unsafe package names remain during lockfile refresh. Current function validation covers correct checked calls, wrong-type arguments, missing checked-argument diagnostics, missing unchecked-argument diagnostics for simple functions, extra-argument diagnostics, and beginner-facing unknown-function diagnostics for mistyped modern `DO` and compatibility `CALL ... WITH` calls; current object-method parameter validation covers correct modern `DO object.method ...` and compatibility `CALL object.method WITH ...` checked calls, wrong-type diagnostics for both call forms, checked methods after another method in the same class, missing and extra checked-argument diagnostics including the extra-argument case for a checked method after another method in the same class, missing-object guidance when `DO player.method ...` or compatibility `CALL object.method WITH ...` appears before `NEW` even if the method name is also wrong, and a class-specific unknown-method diagnostic when a learner calls a method the class does not declare; object-field validation covers correct NUMBER, TEXT, and YESNO direct `SET object.field value` assignments, direct `CHECK TYPE` metadata acceptance for NUMBER/TEXT/YESNO fields, negative NUMBER/TEXT/YESNO metadata mismatches, NUMBER/TEXT/YESNO-expectation unknown-field `CHECK TYPE` diagnostics, missing-object field assignment and `CHECK TYPE` diagnostics, NUMBER/TEXT/YESNO wrong-type direct assignments, field collection when a `HAS` field appears after a simple method, NUMBER/TEXT/YESNO-valued unknown-field diagnostics, and a beginner-facing unknown-field diagnostic when an undeclared field assignment uses an expression whose type is not inferable yet.
4. Add small examples for each foundation feature before adding bigger syntax.
## Complete-platform milestones
+2 -2
View File
@@ -601,7 +601,7 @@ static int typecheck_file(const char *path){ FILE *f=fopen(path,"rb"); char line
else if(!strcmp(up,"TYPE")&&starts_ci(t,"TYPE OF")){ char *name=check_var_after_as(t); if(name){ type_env_set(&types,name,"TEXT"); free(name); } }
else if(!strcmp(up,"NEW")){ const char *as=find_word_ci(t,"AS"); char *name=NULL; char *cls=NULL; char objtype[256]; if(as){ cls=substr(t+3,as); name=xstrdup(trim_inplace((char*)as+2)); } else { const char *pcur=t+3; cls=unquote_token(&pcur); name=unquote_token(&pcur); } snprintf(objtype,sizeof(objtype),"OBJECT:%s",trim_inplace(cls)); if(name&&*trim_inplace(name)){ TypeFieldCheck *fc; char fullname[256]; char *nt=trim_inplace(name); char *ct=trim_inplace(cls); type_env_set(&types,nt,objtype); for(fc=field_checks;fc;fc=fc->next){ if(ci_eq(fc->cls,ct)){ snprintf(fullname,sizeof(fullname),"%s.%s",nt,fc->field); type_env_set(&types,fullname,fc->type); } } } free(cls); free(name); }
else if((!strcmp(up,"DO")&&!find_word_ci(t,"TIMES"))||!strcmp(up,"CALL")){ char *fname=NULL; char **parts=NULL; int ac=0,i,is_method=0; char lookup[256],display[256]; if(!strcmp(up,"DO")){ const char *pcur=t+2; fname=unquote_token(&pcur); if(*trim_inplace((char*)pcur)) ac=split_args(pcur,&parts); } else { char *rest=t+4; const char *with=find_word_ci(rest,"WITH"); fname=with?substr(rest,with):xstrdup(rest); if(with) ac=split_args(with+4,&parts); } snprintf(lookup,sizeof(lookup),"%s",trim_inplace(fname)); snprintf(display,sizeof(display),"%s",lookup); { char *dot=strchr(lookup,'.'); if(dot){ char objname[128]; const char *objtype; snprintf(objname,sizeof(objname),"%.*s",(int)(dot-lookup),lookup); objtype=type_env_get(types,objname); if(objtype&&starts_ci(objtype,"OBJECT:")){ char method[128]; const char *cls=objtype+7; snprintf(method,sizeof(method),"%s",dot+1); if(!type_method_check_for(method_checks,cls,method)){ printf("%s:%d: Object %s has no method %s. Check the method name or add TEACH %s inside CLASS %s.\n",path,line_no,cls,method,method,cls); errs++; } snprintf(lookup,sizeof(lookup),"%s.%s",cls,method); snprintf(display,sizeof(display),"%s",lookup); is_method=1; }
else if(!objtype||(!starts_ci(objtype,"MODULE")&&(!strcmp(up,"DO")||type_method_name_exists(method_checks,dot+1)))){ printf("%s:%d: Object %s is not known yet. Create it with NEW ClassName %s before calling %s.\n",path,line_no,objname,objname,lookup); errs++; } } } for(i=0;i<ac;i++){ const char *param=NULL; const char *need=type_param_check_for(param_checks,lookup,i,&param); const char *got=simple_expr_type(types,parts[i]); if(need&&got&&!type_words_match(need,got)){ printf("%s:%d: Type mismatch for %s %s: parameter %s needs %s, but this argument looks like %s.\n",path,line_no,is_method?"method":"function",display,param?param:"argument",need,got); errs++; } } { TypeParamCheck *pc=param_checks; while(pc){ if(ci_eq(pc->func,lookup)&&pc->pos>=ac){ printf("%s:%d: %s %s needs argument %s as %s, but this call does not provide it.\n",path,line_no,is_method?"Method":"Function",display,pc->param,pc->type); errs++; } pc=pc->next; } } { int expected=type_arity_check_for(arity_checks,lookup); if(expected>=0&&ac>expected){ printf("%s:%d: %s %s only accepts %d %s, but this call gives %d. Remove the extra %s.\n",path,line_no,is_method?"Method":"Function",display,expected,expected==1?"argument":"arguments",ac,ac-expected==1?"argument":"arguments"); errs++; } else if((!strcmp(up,"DO")||!strcmp(up,"CALL"))&&!is_method&&!strchr(lookup,'.')&&expected<0){ printf("%s:%d: Function %s is not known yet. Check the function name or add TEACH %s before calling it.\n",path,line_no,lookup,lookup); errs++; } } free(fname); }
else if(!objtype||(!starts_ci(objtype,"MODULE")&&(!strcmp(up,"DO")||type_method_name_exists(method_checks,dot+1)))){ printf("%s:%d: Object %s is not known yet. Create it with NEW ClassName %s before calling %s.\n",path,line_no,objname,objname,lookup); errs++; } } } for(i=0;i<ac;i++){ const char *param=NULL; const char *need=type_param_check_for(param_checks,lookup,i,&param); const char *got=simple_expr_type(types,parts[i]); if(need&&got&&!type_words_match(need,got)){ printf("%s:%d: Type mismatch for %s %s: parameter %s needs %s, but this argument looks like %s.\n",path,line_no,is_method?"method":"function",display,param?param:"argument",need,got); errs++; } } { TypeParamCheck *pc=param_checks; while(pc){ if(ci_eq(pc->func,lookup)&&pc->pos>=ac){ printf("%s:%d: %s %s needs argument %s as %s, but this call does not provide it.\n",path,line_no,is_method?"Method":"Function",display,pc->param,pc->type); errs++; } pc=pc->next; } } { int expected=type_arity_check_for(arity_checks,lookup); if(expected>=0&&ac>expected){ printf("%s:%d: %s %s only accepts %d %s, but this call gives %d. Remove the extra %s.\n",path,line_no,is_method?"Method":"Function",display,expected,expected==1?"argument":"arguments",ac,ac-expected==1?"argument":"arguments"); errs++; } else if(expected>=0&&ac<expected){ int has_checked_missing=0; TypeParamCheck *mpc=param_checks; while(mpc){ if(ci_eq(mpc->func,lookup)&&mpc->pos>=ac){ has_checked_missing=1; break; } mpc=mpc->next; } if(!has_checked_missing){ printf("%s:%d: %s %s needs %d %s, but this call gives %d. Add the missing %s.\n",path,line_no,is_method?"Method":"Function",display,expected,expected==1?"argument":"arguments",ac,expected-ac==1?"argument":"arguments"); errs++; } } else if((!strcmp(up,"DO")||!strcmp(up,"CALL"))&&!is_method&&!strchr(lookup,'.')&&expected<0){ printf("%s:%d: Function %s is not known yet. Check the function name or add TEACH %s before calling it.\n",path,line_no,lookup,lookup); errs++; } } free(fname); }
else if(!strcmp(up,"CHECK")&&starts_ci(t,"CHECK TYPE")){ const char *is=find_word_ci(t,"IS"); if(is){ char *expr=substr(t+10,is); char *need=xstrdup(trim_inplace((char*)is+2)); char *et=trim_inplace(expr); const char *got=simple_expr_type(types,et); if(got&&!type_words_match(need,got)){ printf("%s:%d: Type check failed: expected %s, but %s looks like %s.\n",path,line_no,need,et,got); errs++; } else if(!got&&strchr(et,'.')){ char objname[128],fieldname[128]; char *dot=strchr(et,'.'); const char *objtype; snprintf(objname,sizeof(objname),"%.*s",(int)(dot-et),et); snprintf(fieldname,sizeof(fieldname),"%s",dot+1); objtype=type_env_get(types,objname); if(objtype&&starts_ci(objtype,"OBJECT:")&&!type_field_check_for(field_checks,objtype+7,fieldname)){ printf("%s:%d: Object %s has no field %s. Check the field name or add HAS %s %s to the class.\n",path,line_no,objtype+7,fieldname,fieldname,need); errs++; } else if(!objtype){ printf("%s:%d: Object %s is not known yet. Create it with NEW ClassName %s before checking %s.\n",path,line_no,objname,objname,et); errs++; } } free(expr); free(need); } else { printf("%s:%d: CHECK TYPE needs IS. Try: CHECK TYPE score IS NUMBER\n",path,line_no); errs++; } }
}
fclose(f); if(errs==0) printf("Type check OK\n"); return errs?1:0; }
@@ -683,6 +683,6 @@ static void print_help(void){
static int show_examples(void){ const char *items[]={"hello.claro","name_input.claro","quiz.claro","calculator.claro","guessing_game.claro","shopping_list.claro","save_and_load_file.claro","simple_functions.claro","text_and_lists.claro","text_polish.claro","practical_scripting.claro","type_hardening.claro","typed_ask.claro","objects_classes.claro","networking.claro",NULL}; int i; printf("Included beginner examples:\n"); for(i=0;items[i];i++) printf(" examples/%s\n",items[i]); printf("\nRun one with: claro examples/hello.claro\n"); return 0; }
static int file_exists_simple(const char *path){ FILE *f=fopen(path,"rb"); if(f){ fclose(f); return 1; } return 0; }
static int run_doctor(void){ int ok=1; const char *files[]={"src/claro.c","README.md","assets/Claro_Logo.jpg","lessons/01_hello.claro","examples/hello.claro","tests/01_hello.claro",NULL}; int i; printf("%s\n",CLARO_VERSION); printf("Doctor check:\n"); for(i=0;files[i];i++){ int has=file_exists_simple(files[i]); printf(" %s %s\n",has?"OK":"MISSING",files[i]); if(!has) ok=0; } printf("%s\n",ok?"Claro folder looks ready.":"Some Claro files are missing."); return ok?0:1; }
static int run_validate(void){ int fails=0, i; const char *checks[]={"lessons/01_hello.claro","lessons/02_ask_name.claro","lessons/03_variables.claro","lessons/04_math.claro","lessons/05_if_else.claro","lessons/06_loops.claro","lessons/07_lists.claro","lessons/08_functions.claro","lessons/09_files.claro","lessons/10_final_quiz.claro","examples/hello.claro","examples/name_input.claro","examples/quiz.claro","examples/calculator.claro","examples/guessing_game.claro","examples/shopping_list.claro","examples/save_and_load_file.claro","examples/simple_functions.claro","examples/text_and_lists.claro","examples/text_polish.claro","examples/practical_scripting.claro","examples/type_hardening.claro","examples/objects_classes.claro","examples/networking.claro",NULL}; printf("%s\n",CLARO_VERSION); printf("Stable package validation:\n"); fails+=run_doctor(); fails+=run_tests(); printf("Checking lessons and main examples:\n"); for(i=0;checks[i];i++){ printf(" %s\n",checks[i]); fails+=check_file(checks[i]); } fails+=typecheck_file("tests/typecheck_good.claro"); fails+=typecheck_file("tests/typecheck_container_good.claro"); fails+=typecheck_file("tests/typecheck_function_good.claro"); fails+=typecheck_file("tests/typecheck_function_multi_good.claro"); fails+=typecheck_file("tests/typecheck_method_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_text_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_yesno_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_check_type_number_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_check_type_text_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_check_type_text_yesno_good.claro"); fails+=typecheck_file("tests/37_object_field_types.claro"); if(typecheck_file("tests/typecheck_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_container_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_function_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_function_multi_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_function_unknown_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_method_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_text_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_yesno_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_unknown_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_unknown_text_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_unknown_yesno_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_unknown_expression_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_text_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_yesno_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_number_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_unknown_number_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_unknown_text_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_unknown_yesno_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_unknown_object_bad.claro")==0) fails++; printf("%s\n",fails?"Validation found problems.":"Validation passed. Claro v1.18.26 foundation checks are ready for use."); return fails?1:0; }
static int run_validate(void){ int fails=0, i; const char *checks[]={"lessons/01_hello.claro","lessons/02_ask_name.claro","lessons/03_variables.claro","lessons/04_math.claro","lessons/05_if_else.claro","lessons/06_loops.claro","lessons/07_lists.claro","lessons/08_functions.claro","lessons/09_files.claro","lessons/10_final_quiz.claro","examples/hello.claro","examples/name_input.claro","examples/quiz.claro","examples/calculator.claro","examples/guessing_game.claro","examples/shopping_list.claro","examples/save_and_load_file.claro","examples/simple_functions.claro","examples/text_and_lists.claro","examples/text_polish.claro","examples/practical_scripting.claro","examples/type_hardening.claro","examples/objects_classes.claro","examples/networking.claro",NULL}; printf("%s\n",CLARO_VERSION); printf("Stable package validation:\n"); fails+=run_doctor(); fails+=run_tests(); printf("Checking lessons and main examples:\n"); for(i=0;checks[i];i++){ printf(" %s\n",checks[i]); fails+=check_file(checks[i]); } fails+=typecheck_file("tests/typecheck_good.claro"); fails+=typecheck_file("tests/typecheck_container_good.claro"); fails+=typecheck_file("tests/typecheck_function_good.claro"); fails+=typecheck_file("tests/typecheck_function_multi_good.claro"); fails+=typecheck_file("tests/typecheck_method_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_text_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_yesno_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_check_type_number_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_check_type_text_good.claro"); fails+=typecheck_file("tests/typecheck_object_field_check_type_text_yesno_good.claro"); fails+=typecheck_file("tests/37_object_field_types.claro"); if(typecheck_file("tests/typecheck_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_container_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_function_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_function_multi_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_function_missing_unchecked_arg_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_function_unknown_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_method_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_text_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_yesno_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_unknown_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_unknown_text_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_unknown_yesno_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_unknown_expression_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_text_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_yesno_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_number_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_unknown_number_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_unknown_text_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_unknown_yesno_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_object_field_check_type_unknown_object_bad.claro")==0) fails++; printf("%s\n",fails?"Validation found problems.":"Validation passed. Claro v1.18.26 foundation checks are ready for use."); return fails?1:0; }
int main(int argc,char **argv){ int arg=1, trace=0; if(argc<2){ print_help(); return 0;} if(strcmp(argv[arg],"--trace")==0||strcmp(argv[arg],"trace")==0){ trace=1; arg++; } if(arg>=argc) return 0; if(strcmp(argv[arg],"help")==0||strcmp(argv[arg],"--help")==0){ print_help(); return 0; } if(strcmp(argv[arg],"test")==0) return run_tests(); if(strcmp(argv[arg],"repl")==0) return run_repl(); if(strcmp(argv[arg],"examples")==0) return show_examples(); if(strcmp(argv[arg],"doctor")==0) return run_doctor(); if(strcmp(argv[arg],"validate")==0) return run_validate(); if(strcmp(argv[arg],"package")==0) return run_package_cmd(argc,argv,arg+1); if(strcmp(argv[arg],"ide")==0) return print_ide_info(); if(strcmp(argv[arg],"new")==0&&arg+1<argc) return create_new_project(argv[arg+1]); if(strcmp(argv[arg],"fmt")==0&&arg+1<argc) return fmt_file(argv[arg+1]); if(strcmp(argv[arg],"check")==0&&arg+1<argc) return check_file(argv[arg+1]); if(strcmp(argv[arg],"typecheck")==0&&arg+1<argc) return typecheck_file(argv[arg+1]); if(strcmp(argv[arg],"version")==0||strcmp(argv[arg],"--version")==0){ puts(CLARO_VERSION); return 0; } if(strcmp(argv[arg],"run")==0){ arg++; if(arg>=argc){ Runtime rt; int rc; char *mainfile=project_value("main"); if(!mainfile||!*mainfile){ if(mainfile) free(mainfile); mainfile=xstrdup("main.claro"); } rt_init(&rt); rt.trace=trace; rt.script_argc=0; rt.script_argv=NULL; rc=run_file(&rt,mainfile); free(mainfile); return rc; } } { Runtime rt; int rc; rt_init(&rt); rt.trace=trace; rt.script_argc=argc-arg-1; rt.script_argv=argv+arg+1; rc=run_file(&rt,argv[arg]); return rc; } }
@@ -0,0 +1,5 @@
TEACH greet name
SAY name
END
DO greet
+3
View File
@@ -26,6 +26,9 @@ EXPECTED = {
"tests/typecheck_function_missing_arg_bad.claro": [
"tests/typecheck_function_missing_arg_bad.claro:6: Function square needs argument amount as NUMBER, but this call does not provide it.",
],
"tests/typecheck_function_missing_unchecked_arg_bad.claro": [
"tests/typecheck_function_missing_unchecked_arg_bad.claro:5: Function greet needs 1 argument, but this call gives 0. Add the missing argument.",
],
"tests/typecheck_function_extra_arg_bad.claro": [
"tests/typecheck_function_extra_arg_bad.claro:6: Function square only accepts 1 argument, but this call gives 2. Remove the extra argument.",
],