docs: clarify Claro v1 status and validation
This commit is contained in:
+54
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Claro v1.17.26 - Networking Reliability Release
|
||||
Claro v1.18.26 - Networking Reliability Release
|
||||
|
||||
A compact, buildable Claro interpreter focused on the beginner-friendly
|
||||
teaching core: readable commands, simple expressions, functions, collections,
|
||||
@@ -42,7 +42,7 @@ int pclose(FILE *stream);
|
||||
#define F_OK 0
|
||||
#endif
|
||||
|
||||
#define CLARO_VERSION "Claro v1.17.26"
|
||||
#define CLARO_VERSION "Claro v1.18.26"
|
||||
|
||||
static void *xmalloc(size_t n){ void *p=malloc(n?n:1); if(!p){ fprintf(stderr,"Out of memory\n"); exit(1);} return p; }
|
||||
static void *xrealloc(void *p,size_t n){ void *q=realloc(p,n?n:1); if(!q){ fprintf(stderr,"Out of memory\n"); exit(1);} return q; }
|
||||
@@ -121,6 +121,7 @@ static void rt_set(Runtime *rt,const char *name,Value val){ Var **head=rt->local
|
||||
static void rt_set_global(Runtime *rt,const char *name,Value val){ Var *v=env_find(rt->globals,name); if(v){ v->val=v_copy(val); return;} v=(Var*)xmalloc(sizeof(Var)); v->name=xstrdup(name); v->val=v_copy(val); v->next=rt->globals; rt->globals=v; }
|
||||
|
||||
static void rt_error(Runtime *rt,const char *file,int line,const char *fmt,...);
|
||||
static char *normalize_path_copy(const char *path){ char *out=xstrdup(path?path:""); char *p; for(p=out;*p;p++) if(*p=='\\') *p='/'; return out; }
|
||||
static int claro_is_type_word(const char *s){ return s&&(ci_eq(s,"NUMBER")||ci_eq(s,"TEXT")||ci_eq(s,"YESNO")||ci_eq(s,"BOOL")||ci_eq(s,"BOOLEAN")||ci_eq(s,"LIST")||ci_eq(s,"MAP")||ci_eq(s,"OBJECT")||ci_eq(s,"ANY")); }
|
||||
static const char *claro_value_type(Value v){ if(v.type==V_NUM) return "NUMBER"; if(v.type==V_STR) return "TEXT"; if(v.type==V_BOOL) return "YESNO"; if(v.type==V_LIST) return "LIST"; if(v.type==V_MAP) return "MAP"; return "NONE"; }
|
||||
static Value claro_default_for_type(const char *type){ if(ci_eq(type,"NUMBER")) return v_num(0); if(ci_eq(type,"TEXT")) return v_str(""); if(ci_eq(type,"YESNO")||ci_eq(type,"BOOL")||ci_eq(type,"BOOLEAN")) return v_bool(0); if(ci_eq(type,"LIST")) return v_list(); if(ci_eq(type,"MAP")||ci_eq(type,"OBJECT")) return v_map(); return v_none(); }
|
||||
@@ -134,7 +135,7 @@ static int rt_set_checked(Runtime *rt,const char *file,int line,const char *name
|
||||
rt_set(rt,name,val); return 1; }
|
||||
static void graphics_note(Runtime *rt,const char *what){ (void)what; rt_set(rt,"GRAPHICS_READY",v_bool(1)); }
|
||||
|
||||
static void rt_error(Runtime *rt,const char *file,int line,const char *fmt,...){ va_list ap; char buf[1024]; if(rt->error) return; va_start(ap,fmt); vsnprintf(buf,sizeof(buf),fmt,ap); va_end(ap); rt->error=1; rt->err_msg=xstrdup(buf); rt->err_file=xstrdup(file?file:""); rt->err_line=line; rt_set(rt,"LASTERROR",v_str(buf)); rt_set(rt,"LASTERRORFILE",v_str(file?file:"")); rt_set(rt,"LASTERRORLINE",v_num(line)); }
|
||||
static void rt_error(Runtime *rt,const char *file,int line,const char *fmt,...){ va_list ap; char buf[1024]; char *nfile; if(rt->error) return; va_start(ap,fmt); vsnprintf(buf,sizeof(buf),fmt,ap); va_end(ap); nfile=normalize_path_copy(file?file:""); rt->error=1; rt->err_msg=xstrdup(buf); rt->err_file=xstrdup(nfile); rt->err_line=line; rt_set(rt,"LASTERROR",v_str(buf)); rt_set(rt,"LASTERRORFILE",v_str(nfile)); rt_set(rt,"LASTERRORLINE",v_num(line)); free(nfile); }
|
||||
static void rt_clear_error(Runtime *rt){ rt->error=0; }
|
||||
static void out_line(Runtime *rt,Value v){ char *s=v_to_string(v); if(rt->capture){ str_add(&rt->captured,s); str_ch(&rt->captured,'\n'); } else { printf("%s\n",s); } free(s); }
|
||||
static void add_function(Runtime *rt,const char *name,char **params,int pcnt,Program *p,int start,int end){ Function *f=(Function*)xmalloc(sizeof(Function)); int i; f->name=xstrdup(name); f->pcnt=pcnt; f->params=(char**)xmalloc(sizeof(char*)*(pcnt?pcnt:1)); for(i=0;i<pcnt;i++) f->params[i]=xstrdup(params[i]); f->prog=p; f->start=start; f->end=end; f->next=rt->funcs; rt->funcs=f; }
|
||||
@@ -323,7 +324,9 @@ static void exec_line(Runtime *rt,Program *p,int *pcp,const char *raw){ char buf
|
||||
if(strcmp(up,"CLASS")==0){ int end=match_block(p,pc,"CLASS","ENDCLASS",NULL,NULL); *pcp=end<0?pc:end; return; }
|
||||
if(strcmp(up,"NEW")==0){ const char *as=find_word_ci(t,"AS"); if(as){ char *cls=substr(t+3,as); char *var=xstrdup(trim_inplace((char*)as+2)); create_object_value(rt,p->path,pc+1,trim_inplace(cls),trim_inplace(var)); free(cls); free(var); } else { const char *pcur=t+3; char *cls=unquote_token(&pcur); char *var=xstrdup(trim_inplace((char*)pcur)); create_object_value(rt,p->path,pc+1,trim_inplace(cls),trim_inplace(var)); free(cls); free(var); } return; }
|
||||
if(strcmp(up,"START")==0){ if(starts_ci(t+5," TASK")){ const char *pcur=t+10; char *name=unquote_token(&pcur); int end=match_block(p,pc,"START","ENDTASK",NULL,NULL); exec_range(rt,p,pc+1,end); if(name&&*name){ char done[256]; snprintf(done,sizeof(done),"TASK_%s_DONE",trim_inplace(name)); rt_set(rt,done,v_bool(1)); } *pcp=end<0?pc:end; free(name); return; } }
|
||||
if(strcmp(up,"YIELD")==0){ return; }
|
||||
if(strcmp(up,"WAIT")==0){ return; }
|
||||
if(strcmp(up,"TASK")==0){ if(starts_ci(t+4," STATUS")){ const char *as=find_word_ci(t,"AS"); if(as){ char *name=substr(t+11,as); char *var=xstrdup(trim_inplace((char*)as+2)); char key[256]; Value done; snprintf(key,sizeof(key),"TASK_%s_DONE",trim_inplace(name)); done=rt_get(rt,key); rt_set(rt,var,v_str(v_truth(done)?"DONE":"PENDING")); free(name); free(var); } else rt_error(rt,p->path,pc+1,"TASK STATUS needs AS. Try: TASK STATUS helloTask AS status"); return; } }
|
||||
if(strcmp(up,"OPEN")==0||strcmp(up,"CLEAR")==0||strcmp(up,"DRAW")==0||strcmp(up,"UPDATE")==0||strcmp(up,"CLOSE")==0){ graphics_note(rt,up); return; }
|
||||
if(strcmp(up,"HTTP")==0){
|
||||
const char *as=find_word_ci(t,"AS");
|
||||
@@ -395,7 +398,7 @@ static int run_file(Runtime *rt,const char *path){ Program *p=load_program(rt,pa
|
||||
|
||||
/* ---------- formatter/check/test runner ---------- */
|
||||
static int fmt_file(const char *path){ FILE *f=fopen(path,"rb"); char line[4096]; int indent=0; if(!f){ fprintf(stderr,"Could not open %s\n",path); return 1;} while(fgets(line,sizeof(line),f)){ char *t=trim_inplace(line),w[64],up[64]; int opens=0; first_word(t,w,sizeof(w)); upper_copy(up,w,sizeof(up)); if(!strcmp(up,"ENDIF")||!strcmp(up,"LEARNED")||!strcmp(up,"DONE")||!strcmp(up,"ENDTRY")||!strcmp(up,"ELSE")||!strcmp(up,"CATCH")||!strcmp(up,"ENDCOMMENT")||!strcmp(up,"ENDCLASS")||!strcmp(up,"ENDTASK")||!strcmp(up,"END")) indent-=4; if(indent<0) indent=0; for(int i=0;i<indent;i++) putchar(' '); puts(t); opens=!strcmp(up,"TEACH")||!strcmp(up,"IF")||!strcmp(up,"FOR")||!strcmp(up,"TRY")||!strcmp(up,"CLASS")||!strcmp(up,"START")||!strcmp(up,"COMMENT")||!strcmp(up,"REPEAT")||!strcmp(up,"ELSE")||!strcmp(up,"CATCH")||(!strcmp(up,"DO")&&find_word_ci(t,"TIMES")); if(opens) indent+=4; } fclose(f); return 0; }
|
||||
static const char *check_commands[]={"SAY","SET","ASK","IF","ELSE","ENDIF","DO","DONE","FOR","REPEAT","UNTIL","TEACH","LEARNED","RETURN","CALL","IMPORT","ADD","COUNT","GET","PUT","WRITE","APPEND","READ","EXISTS","DELETE","PARSE","MAKE","TRY","CATCH","ENDTRY","RAISE","CREATE","COPY","MOVE","LIST","TEXT","RANDOM","RUN","SORT","REVERSE","FIND","REMOVE","SHOW","HIDE","EXPORT","COMMENT","ENDCOMMENT","END","WAIT","CLASS","HAS","ENDCLASS","NEW","START","ENDTASK","OPEN","CLEAR","DRAW","UPDATE","CLOSE","HTTP","OBJECT","TYPE","CHECK",NULL};
|
||||
static const char *check_commands[]={"SAY","SET","ASK","IF","ELSE","ENDIF","DO","DONE","FOR","REPEAT","UNTIL","TEACH","LEARNED","RETURN","CALL","IMPORT","ADD","COUNT","GET","PUT","WRITE","APPEND","READ","EXISTS","DELETE","PARSE","MAKE","TRY","CATCH","ENDTRY","RAISE","CREATE","COPY","MOVE","LIST","TEXT","RANDOM","RUN","SORT","REVERSE","FIND","REMOVE","SHOW","HIDE","EXPORT","COMMENT","ENDCOMMENT","END","WAIT","YIELD","TASK","CLASS","HAS","ENDCLASS","NEW","START","ENDTASK","OPEN","CLEAR","DRAW","UPDATE","CLOSE","HTTP","OBJECT","TYPE","CHECK",NULL};
|
||||
static int known_command(const char *up){ int i; for(i=0;check_commands[i];i++) if(strcmp(up,check_commands[i])==0) return 1; return 0; }
|
||||
static int levenshtein(const char *a,const char *b){ int la=(int)strlen(a), lb=(int)strlen(b), i,j; int *dp=(int*)xmalloc(sizeof(int)*(la+1)*(lb+1)); for(i=0;i<=la;i++) dp[i*(lb+1)]=i; for(j=0;j<=lb;j++) dp[j]=j; for(i=1;i<=la;i++) for(j=1;j<=lb;j++){ int c=tolower((unsigned char)a[i-1])==tolower((unsigned char)b[j-1])?0:1; int x=dp[(i-1)*(lb+1)+j]+1, y=dp[i*(lb+1)+j-1]+1, z=dp[(i-1)*(lb+1)+j-1]+c; int m=x<y?x:y; if(z<m)m=z; dp[i*(lb+1)+j]=m; } i=dp[la*(lb+1)+lb]; free(dp); return i; }
|
||||
|
||||
@@ -475,6 +478,9 @@ static int check_file(const char *path){
|
||||
const char *as=find_word_ci(t,"AS");
|
||||
if(as){ char *name=xstrdup(trim_inplace((char*)as+2)); const char *status=find_word_ci(name,"STATUS"); if(status){ char *primary=substr(name,status); check_add_var(&vars,primary); check_add_var(&vars,trim_inplace((char*)status+6)); free(primary); } else check_add_var(&vars,name); free(name); }
|
||||
}
|
||||
if(!strcmp(up,"TASK")){
|
||||
char *name=check_var_after_as(t); if(name){ check_add_var(&vars,name); free(name); }
|
||||
}
|
||||
if(!strcmp(up,"CALL")){
|
||||
char *name=check_var_after_as(t); if(name){ check_add_var(&vars,name); free(name); }
|
||||
}
|
||||
@@ -495,7 +501,7 @@ static int check_file(const char *path){
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
while(sp>0){ CheckBlock b=stack[--sp]; printf("%s:%d: %s block opened here is missing %s\n",path,b.line,b.open,b.expect); errs++; }
|
||||
while(sp>0){ CheckBlock b=stack[--sp]; printf("%s:%d: %s block opened here needs %s\n",path,b.line,b.open,b.expect); errs++; }
|
||||
if(errs==0) printf("OK\n");
|
||||
return errs?1:0;
|
||||
}
|
||||
@@ -503,13 +509,16 @@ static int check_file(const char *path){
|
||||
static const char *type_env_get(Var *types,const char *name){ Var *v=env_find(types,name); if(v&&v->val.type==V_STR) return v->val.str; return NULL; }
|
||||
static void type_env_set(Var **types,const char *name,const char *type){ Var *v; char tmp[256]; char *t; if(!name||!type||!*type) return; strncpy(tmp,name,sizeof(tmp)-1); tmp[sizeof(tmp)-1]=0; t=trim_inplace(tmp); if(!*t) return; v=env_find(*types,t); if(v){ v->val=v_str(type); return; } v=(Var*)xmalloc(sizeof(Var)); memset(v,0,sizeof(Var)); v->name=xstrdup(t); v->val=v_str(type); v->next=*types; *types=v; }
|
||||
static const char *simple_expr_type(Var *types,const char *expr){ char tmp[512]; char *t; double d; size_t i=0; if(!expr) return NULL; strncpy(tmp,expr,sizeof(tmp)-1); tmp[sizeof(tmp)-1]=0; t=trim_inplace(tmp); if(!*t) return NULL; if(*t=='"') return "TEXT"; if(parse_number_strict(t,&d)) return "NUMBER"; if(ci_eq(t,"YES")||ci_eq(t,"NO")||ci_eq(t,"TRUE")||ci_eq(t,"FALSE")) return "YESNO"; if(ci_eq(t,"LIST")) return "LIST"; if(ci_eq(t,"MAP")) return "MAP"; if(starts_ci(t,"NEW ")) return "OBJECT"; while(t[i]&&(isalnum((unsigned char)t[i])||t[i]=='_'||t[i]=='.')) i++; if(i>0 && t[i]==0){ return type_env_get(types,t); } return NULL; }
|
||||
static int type_words_match(const char *need,const char *got){ if(!need||!*need||ci_eq(need,"ANY")) return 1; if(!got||!*got) return 1; if(ci_eq(need,got)) return 1; if((ci_eq(need,"YESNO")||ci_eq(need,"BOOL")||ci_eq(need,"BOOLEAN")) && (ci_eq(got,"YESNO")||ci_eq(got,"BOOL")||ci_eq(got,"BOOLEAN"))) return 1; if(ci_eq(need,"OBJECT") && ci_eq(got,"MAP")) return 1; return 0; }
|
||||
static int type_words_match(const char *need,const char *got){ if(!need||!*need||ci_eq(need,"ANY")) return 1; if(!got||!*got) return 1; if(ci_eq(need,got)) return 1; if(starts_ci(need,"LIST OF") && ci_eq(got,"LIST")) return 1; if(starts_ci(need,"MAP OF") && ci_eq(got,"MAP")) return 1; if((ci_eq(need,"YESNO")||ci_eq(need,"BOOL")||ci_eq(need,"BOOLEAN")) && (ci_eq(got,"YESNO")||ci_eq(got,"BOOL")||ci_eq(got,"BOOLEAN"))) return 1; if(ci_eq(need,"OBJECT") && ci_eq(got,"MAP")) return 1; return 0; }
|
||||
static const char *container_member_type(const char *type,const char *kind){ const char *p; static char buf[128]; if(!type||!kind) return NULL; if(!starts_ci(type,kind)) return NULL; p=type+strlen(kind); while(*p&&isspace((unsigned char)*p)) p++; if(!starts_ci(p,"OF")) return NULL; p+=2; while(*p&&isspace((unsigned char)*p)) p++; if(!*p) return NULL; snprintf(buf,sizeof(buf),"%s",p); return trim_inplace(buf); }
|
||||
static void parse_set_for_typecheck2(const char *t,char **name,char **type,char **expr){ const char *rest=t+3; const char *to=find_word_ci(rest,"TO"); const char *as=find_word_ci(rest,"AS"); *name=NULL; *type=NULL; *expr=NULL; if(as&&to&&as<to){ *name=substr(rest,as); *type=substr(as+2,to); *expr=xstrdup(to+2); return; } if(to){ char *before=substr(rest,to); const char *pcur=before; char *var=unquote_token(&pcur); char *maybe=unquote_token(&pcur); char *mt=trim_inplace(maybe); *name=xstrdup(trim_inplace(var)); if(claro_is_type_word(mt)) *type=xstrdup(mt); *expr=xstrdup(to+2); free(before); free(var); free(maybe); return; } { const char *pcur=rest; char *var=unquote_token(&pcur); const char *after_var=pcur; char *maybe=unquote_token(&pcur); char *mt=trim_inplace(maybe); *name=xstrdup(trim_inplace(var)); if(claro_is_type_word(mt)){ *type=xstrdup(mt); *expr=xstrdup(trim_inplace((char*)pcur)); } else { *expr=xstrdup(trim_inplace((char*)after_var)); } free(var); free(maybe); } }
|
||||
static int typecheck_file(const char *path){ FILE *f=fopen(path,"rb"); char line[4096]; int line_no=0,errs=0; Var *types=NULL; if(!f){ fprintf(stderr,"Could not open %s\n",path); return 1; } 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,"SET")){ char *name=NULL,*type=NULL,*expr=NULL; const char *got,*old; parse_set_for_typecheck2(t,&name,&type,&expr); if(name&&*trim_inplace(name)){ char *nt=trim_inplace(name); char *tt=type?trim_inplace(type):NULL; got=simple_expr_type(types,expr); old=type_env_get(types,nt); if(tt&&*tt){ if(got&&!type_words_match(tt,got)){ printf("%s:%d: %s needs %s, but this looks like %s.\n",path,line_no,nt,tt,got); errs++; } type_env_set(&types,nt,tt); } else if(old){ if(got&&!type_words_match(old,got)){ printf("%s:%d: %s was first set as %s, but this looks like %s.\n",path,line_no,nt,old,got); errs++; } } else if(got) type_env_set(&types,nt,got); else type_env_set(&types,nt,"ANY"); } free(name); free(type); free(expr); }
|
||||
static int typecheck_file(const char *path){ FILE *f=fopen(path,"rb"); char line[4096]; int line_no=0,errs=0; Var *types=NULL; if(!f){ fprintf(stderr,"Could not open %s\n",path); return 1; } 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,"SET")){ char *name=NULL,*type=NULL,*expr=NULL; const char *got,*old; parse_set_for_typecheck2(t,&name,&type,&expr); if(name&&*trim_inplace(name)){ char *nt=trim_inplace(name); char *tt=type?trim_inplace(type):NULL; got=simple_expr_type(types,expr); old=type_env_get(types,nt); if(tt&&*tt){ if(got&&!type_words_match(tt,got)){ printf("%s:%d: Type mismatch for %s: expected %s, but this value looks like %s.\n",path,line_no,nt,tt,got); errs++; } type_env_set(&types,nt,tt); } else if(old){ if(got&&!type_words_match(old,got)){ printf("%s:%d: Type mismatch for %s: it was first set as %s, but this value looks like %s.\n",path,line_no,nt,old,got); errs++; } } else if(got) type_env_set(&types,nt,got); else type_env_set(&types,nt,"ANY"); } free(name); free(type); free(expr); }
|
||||
else if(!strcmp(up,"ADD")){ const char *to=find_word_ci(t,"TO"); if(to){ char *expr=substr(t+3,to); char *name=xstrdup(trim_inplace((char*)to+2)); const char *listtype=type_env_get(types,name); const char *need=container_member_type(listtype,"LIST"); const char *got=simple_expr_type(types,expr); if(need&&got&&!type_words_match(need,got)){ printf("%s:%d: Type mismatch for list %s: expected %s item, but this value looks like %s.\n",path,line_no,name,need,got); errs++; } free(expr); free(name); } }
|
||||
else if(!strcmp(up,"PUT")){ const char *key=find_word_ci(t,"KEY"), *val=find_word_ci(t,"VALUE"); if(key&&val){ char *name=substr(t+3,key); char *expr=xstrdup(trim_inplace((char*)val+5)); char *nt=trim_inplace(name); const char *maptype=type_env_get(types,nt); const char *need=container_member_type(maptype,"MAP"); const char *got=simple_expr_type(types,expr); if(need&&got&&!type_words_match(need,got)){ printf("%s:%d: Type mismatch for map %s: expected %s value, but this value looks like %s.\n",path,line_no,nt,need,got); errs++; } free(name); free(expr); } }
|
||||
else if(!strcmp(up,"ASK")){ const char *as=find_word_ci(t,"AS"); char *name=NULL,*type=NULL; if(as){ const char *pcur=as+2; name=unquote_token(&pcur); { char *rest=xstrdup(trim_inplace((char*)pcur)); if(claro_is_type_word(rest)) type=rest; else free(rest); } } else { const char *pcur=t+3; char *prompt=unquote_token(&pcur); free(prompt); name=unquote_token(&pcur); { char *rest=xstrdup(trim_inplace((char*)pcur)); if(claro_is_type_word(rest)) type=rest; else free(rest); } } if(name&&*trim_inplace(name)) type_env_set(&types,trim_inplace(name),type?type:"TEXT"); free(name); free(type); }
|
||||
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; if(as) name=xstrdup(trim_inplace((char*)as+2)); else { const char *pcur=t+3; char *cls=unquote_token(&pcur); free(cls); name=unquote_token(&pcur); } if(name&&*trim_inplace(name)) type_env_set(&types,trim_inplace(name),"OBJECT"); free(name); }
|
||||
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)); const char *got=simple_expr_type(types,expr); if(got&&!type_words_match(need,got)){ printf("%s:%d: Type check says this should be %s, but it looks like %s.\n",path,line_no,need,got); errs++; } free(expr); free(need); } else { printf("%s:%d: CHECK TYPE needs IS. Try: CHECK TYPE score IS NUMBER\n",path,line_no); errs++; } }
|
||||
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)); const char *got=simple_expr_type(types,expr); 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,trim_inplace(expr),got); 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; }
|
||||
static char *read_file_text(const char *path){ FILE *f=fopen(path,"rb"); Str b; int c; if(!f) return NULL; str_init(&b); while((c=fgetc(f))!=EOF) str_ch(&b,(char)c); fclose(f); return str_take(&b); }
|
||||
@@ -518,28 +527,56 @@ static int run_tests(void){ int fails=0;
|
||||
#ifndef _WIN32
|
||||
DIR *d=opendir("tests"); struct dirent *de; if(!d){ fprintf(stderr,"No tests directory\n"); return 1;} while((de=readdir(d))){ if(strstr(de->d_name,".claro")){ char path[512]; snprintf(path,sizeof(path),"tests/%s",de->d_name); fails+=run_one_test(path); } } closedir(d);
|
||||
#else
|
||||
const char *basic[]={"tests/01_hello.claro","tests/02_math.claro","tests/03_function.claro",NULL}; int i; for(i=0;basic[i];i++) fails+=run_one_test(basic[i]);
|
||||
struct _finddata_t fd; intptr_t h=_findfirst("tests/*.claro",&fd); if(h==-1){ fprintf(stderr,"No tests directory\n"); return 1;} do { char path[512]; snprintf(path,sizeof(path),"tests/%s",fd.name); fails+=run_one_test(path); } while(_findnext(h,&fd)==0); _findclose(h);
|
||||
#endif
|
||||
printf("%s: %d failure(s)\n",fails?"FAIL":"PASS",fails); return fails?1:0; }
|
||||
|
||||
static int write_text_file_simple(const char *path,const char *text){ FILE *f=fopen(path,"wb"); if(!f) return 0; fputs(text,f); fclose(f); return 1; }
|
||||
static int create_new_project(const char *name){ char path[512]; char text[1024]; if(!name||!*name){ fprintf(stderr,"Project needs a name. Try: claro new MyProject\n"); return 1; } if(!make_folder(name)){ fprintf(stderr,"Could not create project folder: %s\n",name); return 1; } snprintf(path,sizeof(path),"%s/main.claro",name); write_text_file_simple(path,"SAY \"Welcome to Claro!\"\n\nSET name TO \"Learner\"\nSAY \"Hello \" + name\n\nTEACH greet person\n SAY \"Nice to meet you, \" + person\nEND\n\nDO greet \"Friend\"\n"); snprintf(path,sizeof(path),"%s/packages",name); make_folder(path); snprintf(path,sizeof(path),"%s/claro.project",name); snprintf(text,sizeof(text),"name: %s\nmain: main.claro\nversion: v1.17.26\npackages:\n",name); write_text_file_simple(path,text); snprintf(path,sizeof(path),"%s/claro.lock",name); write_text_file_simple(path,"# Claro package lock\nversion: v1.17.26\n"); snprintf(path,sizeof(path),"%s/README.md",name); write_text_file_simple(path,"# My Claro Project\n\nBuild Claro, then run this project with:\n\n```bash\nclaro run\n```\n\nUse packages with:\n\n```bash\nclaro package add text\nclaro package list\nclaro package doctor\n```\n"); printf("Created Claro project: %s\n",name); printf("Next steps:\n cd %s\n claro run\n",name); return 0; }
|
||||
static int create_new_project(const char *name){ char path[512]; char text[1024]; if(!name||!*name){ fprintf(stderr,"Project needs a name. Try: claro new MyProject\n"); return 1; } if(!make_folder(name)){ fprintf(stderr,"Could not create project folder: %s\n",name); return 1; } snprintf(path,sizeof(path),"%s/main.claro",name); write_text_file_simple(path,"SAY \"Welcome to Claro!\"\n\nSET name TO \"Learner\"\nSAY \"Hello \" + name\n\nTEACH greet person\n SAY \"Nice to meet you, \" + person\nEND\n\nDO greet \"Friend\"\n"); snprintf(path,sizeof(path),"%s/packages",name); make_folder(path); snprintf(path,sizeof(path),"%s/claro.project",name); snprintf(text,sizeof(text),"name: %s\nmain: main.claro\nversion: v1.18.26\npackages:\n",name); write_text_file_simple(path,text); snprintf(path,sizeof(path),"%s/claro.lock",name); write_text_file_simple(path,"# Claro package lock\nversion: v1.18.26\n"); snprintf(path,sizeof(path),"%s/README.md",name); write_text_file_simple(path,"# My Claro Project\n\nBuild Claro, then run this project with:\n\n```bash\nclaro run\n```\n\nUse packages with:\n\n```bash\nclaro package add text\nclaro package list\nclaro package doctor\n```\n"); printf("Created Claro project: %s\n",name); printf("Next steps:\n cd %s\n claro run\n",name); return 0; }
|
||||
static int run_repl(void){ Runtime rt; char line[4096]; Program p; rt_init(&rt); memset(&p,0,sizeof(p)); p.path=xstrdup("<repl>"); p.count=1; p.cap=1; p.lines=(char**)xmalloc(sizeof(char*)); printf("%s\n",CLARO_VERSION); printf("Type HELP for help, or EXIT to leave.\n"); while(1){ int pc=0; printf("> "); fflush(stdout); if(!fgets(line,sizeof(line),stdin)) break; { size_t n=strlen(line); while(n&&(line[n-1]=='\n'||line[n-1]=='\r')) line[--n]=0; } { char *t=trim_inplace(line); if(ci_eq(t,"EXIT")||ci_eq(t,"QUIT")) break; if(ci_eq(t,"HELP")){ printf("Try: SAY \"Hello\"\n"); printf("Try: SET name TO \"Jon\"\n"); printf("Try: SAY name\n"); continue; } if(!*t) continue; p.lines[0]=t; exec_line(&rt,&p,&pc,t); if(rt.error){ fprintf(stderr,"%s:%d: %s\n",rt.err_file?rt.err_file:"<repl>",rt.err_line,rt.err_msg?rt.err_msg:"error"); rt_clear_error(&rt); } } } return 0; }
|
||||
|
||||
static int file_exists_simple(const char *path);
|
||||
static int path_exists_simple(const char *path){ struct stat st; return path&&*path&&stat(path,&st)==0; }
|
||||
static int package_name_safe(const char *name){ int i; if(!name||!*name) return 0; if(name[0]=='.'||name[0]=='-'||name[0]=='_') return 0; for(i=0;name[i];i++){ unsigned char c=(unsigned char)name[i]; if(!(isalnum(c)||c=='_'||c=='-')) return 0; } return 1; }
|
||||
static void ensure_project_file(void){ if(!file_exists_simple("claro.project")) write_text_file_simple("claro.project","name: ClaroProject\nmain: main.claro\nversion: v1.17.26\npackages:\n"); }
|
||||
static void package_checksum(const char *name,char *out,size_t n){ unsigned long h=5381; const char *p=name?name:""; while(*p){ h=((h<<5)+h)+(unsigned char)(*p++); } p="|local|1|claro"; while(*p){ h=((h<<5)+h)+(unsigned char)(*p++); } snprintf(out,n,"%08lx",h); }
|
||||
static void ensure_project_file(void){ if(!file_exists_simple("claro.project")) write_text_file_simple("claro.project","manifest-version: 1\nname: ClaroProject\nmain: main.claro\nversion: v1.18.26\npackages:\n"); }
|
||||
static char *project_value(const char *key){ char *txt=read_file_text("claro.project"); size_t kn=strlen(key); char *p,*out=NULL; if(!txt) return NULL; p=txt; while(*p){ char *line=p; char save; while(*p&&*p!='\n'&&*p!='\r') p++; save=*p; *p=0; { char *t=trim_inplace(line); if(strnicmp2(t,key,kn)==0 && t[kn]==':'){ out=xstrdup(trim_inplace(t+kn+1)); break; } } if(save) p++; while(*p=='\n'||*p=='\r') p++; } free(txt); return out; }
|
||||
static int package_has_name(const char *name){ char *txt=read_file_text("claro.project"); char *p; int found=0; if(!txt) return 0; p=txt; while(*p){ char *line=p; char save; while(*p&&*p!='\n'&&*p!='\r') p++; save=*p; *p=0; { char *t=trim_inplace(line); if(strnicmp2(t,"package:",8)==0){ char *pkg=trim_inplace(t+8); if(strcmp(pkg,name)==0){ found=1; break; } } } if(save) p++; while(*p=='\n'||*p=='\r') p++; } free(txt); return found; }
|
||||
static int write_package_lock(void){ char *txt=read_file_text("claro.project"); FILE *f; char *p; if(!txt) return 0; f=fopen("claro.lock","wb"); if(!f){ free(txt); return 0; } fputs("# Claro package lock\nversion: v1.17.26\n",f); p=txt; while(*p){ char *line=p; char save; while(*p&&*p!='\n'&&*p!='\r') p++; save=*p; *p=0; { char *t=trim_inplace(line); if(strnicmp2(t,"package:",8)==0){ char *pkg=trim_inplace(t+8); if(*pkg) fprintf(f,"package: %s\n",pkg); } } if(save) p++; while(*p=='\n'||*p=='\r') p++; } fclose(f); free(txt); return 1; }
|
||||
static int write_package_lock(void){ char *txt=read_file_text("claro.project"); FILE *f; char *p; if(!txt) return 0; f=fopen("claro.lock","wb"); if(!f){ free(txt); return 0; } fputs("# Claro package lock\nlock-version: 1\nversion: v1.18.26\n",f); p=txt; while(*p){ char *line=p; char save; while(*p&&*p!='\n'&&*p!='\r') p++; save=*p; *p=0; { char *t=trim_inplace(line); if(strnicmp2(t,"package:",8)==0){ char *pkg=trim_inplace(t+8); if(*pkg){ char sum[32]; package_checksum(pkg,sum,sizeof(sum)); fprintf(f,"package: %s\nchecksum: %s\n",pkg,sum); } } } if(save) p++; while(*p=='\n'||*p=='\r') p++; } fclose(f); free(txt); return 1; }
|
||||
static int append_package_to_project(const char *name){ FILE *f; if(!package_name_safe(name)){ fprintf(stderr,"Package names may use only letters, numbers, dash, and underscore.\n"); return 0; } ensure_project_file(); if(package_has_name(name)){ printf("Package already listed: %s\n",name); return 1; } f=fopen("claro.project","ab"); if(!f) return 0; fprintf(f,"package: %s\n",name); fclose(f); write_package_lock(); return 1; }
|
||||
static int remove_package_from_project(const char *name){ char *txt=read_file_text("claro.project"); FILE *f; char *p; int removed=0; if(!txt) return 0; f=fopen("claro.project","wb"); if(!f){ free(txt); return 0; } p=txt; while(*p){ char *line=p; char save; int skip=0; while(*p&&*p!='\n'&&*p!='\r') p++; save=*p; *p=0; { char *copy=xstrdup(line); char *t=trim_inplace(copy); if(strnicmp2(t,"package:",8)==0){ char *pkg=trim_inplace(t+8); if(strcmp(pkg,name)==0){ skip=1; removed=1; } } free(copy); } if(!skip) fprintf(f,"%s\n",line); if(save) p++; while(*p=='\n'||*p=='\r') p++; } fclose(f); free(txt); write_package_lock(); return removed; }
|
||||
static void create_package_folder(const char *name){ char path[512], meta[512], readme[512]; make_folder("packages"); snprintf(path,sizeof(path),"packages/%s",name); make_folder(path); snprintf(meta,sizeof(meta),"%s/claro.package",path); if(!file_exists_simple(meta)){ char text[512]; snprintf(text,sizeof(text),"name: %s\nversion: 1\n",name); write_text_file_simple(meta,text); } snprintf(readme,sizeof(readme),"%s/README.md",path); if(!file_exists_simple(readme)){ char text[512]; snprintf(text,sizeof(text),"# %s\n\nThis is a local Claro package folder.\n",name); write_text_file_simple(readme,text); } }
|
||||
static void create_package_folder(const char *name){ char path[512], meta[512], readme[512], sum[32]; make_folder("packages"); snprintf(path,sizeof(path),"packages/%s",name); make_folder(path); snprintf(meta,sizeof(meta),"%s/claro.package",path); package_checksum(name,sum,sizeof(sum)); { char text[1024]; snprintf(text,sizeof(text),"manifest-version: 1\nname: %s\nversion: 1\nsource: local\nchecksum: %s\n",name,sum); write_text_file_simple(meta,text); } snprintf(readme,sizeof(readme),"%s/README.md",path); if(!file_exists_simple(readme)){ char text[512]; snprintf(text,sizeof(text),"# %s\n\nThis is a local Claro package folder.\n",name); write_text_file_simple(readme,text); } }
|
||||
static int list_project_packages(void){ char *txt=read_file_text("claro.project"); char *p; int count=0; printf("Packages in claro.project:\n"); if(!txt){ printf(" (no claro.project yet)\n"); return 0; } p=txt; while(*p){ char *line=p; char save; while(*p&&*p!='\n'&&*p!='\r') p++; save=*p; *p=0; { char *t=trim_inplace(line); if(strnicmp2(t,"package:",8)==0){ char *pkg=trim_inplace(t+8); if(*pkg){ printf(" %s\n",pkg); count++; } } } if(save) p++; while(*p=='\n'||*p=='\r') p++; } if(!count) printf(" (none)\n"); free(txt); return 0; }
|
||||
static int package_doctor(void){ int ok=1; char *mainfile; printf("%s\n",CLARO_VERSION); printf("Package/project doctor:\n"); printf(" %s claro.project\n",file_exists_simple("claro.project")?"OK":"MISSING"); if(!file_exists_simple("claro.project")) ok=0; mainfile=project_value("main"); if(mainfile&&*mainfile){ printf(" %s main script: %s\n",file_exists_simple(mainfile)?"OK":"MISSING",mainfile); if(!file_exists_simple(mainfile)) ok=0; } else { printf(" MISSING main setting\n"); ok=0; } printf(" %s packages folder\n",path_exists_simple("packages")?"OK":"MISSING"); if(!path_exists_simple("packages")) ok=0; printf(" %s claro.lock\n",file_exists_simple("claro.lock")?"OK":"MISSING"); if(!file_exists_simple("claro.lock")) ok=0; free(mainfile); printf("%s\n",ok?"Package/project files look ready.":"Package/project files need attention."); return ok?0:1; }
|
||||
static int run_package_cmd(int argc,char **argv,int arg){ if(arg>=argc){ printf("Package commands:\n claro package init\n claro package add NAME\n claro package remove NAME\n claro package list\n claro package doctor\n claro package lock\n"); return 0; } if(strcmp(argv[arg],"init")==0){ ensure_project_file(); make_folder("packages"); write_package_lock(); printf("Package project ready: claro.project, claro.lock, packages/\n"); return 0; } if(strcmp(argv[arg],"add")==0&&arg+1<argc){ const char *name=argv[arg+1]; int already; if(!package_name_safe(name)){ fprintf(stderr,"Package names may use only letters, numbers, dash, and underscore.\n"); return 1; } make_folder("packages"); already=package_has_name(name); if(!append_package_to_project(name)) return 1; create_package_folder(name); if(!already) printf("Added package: %s\n",name); return 0; } if(strcmp(argv[arg],"remove")==0&&arg+1<argc){ const char *name=argv[arg+1]; if(!package_name_safe(name)){ fprintf(stderr,"Package names may use only letters, numbers, dash, and underscore.\n"); return 1; } if(remove_package_from_project(name)) printf("Removed package from project: %s\n",name); else printf("Package was not listed: %s\n",name); return 0; } if(strcmp(argv[arg],"list")==0) return list_project_packages(); if(strcmp(argv[arg],"doctor")==0) return package_doctor(); if(strcmp(argv[arg],"lock")==0||strcmp(argv[arg],"update")==0){ ensure_project_file(); make_folder("packages"); if(write_package_lock()){ printf("Updated claro.lock\n"); return 0; } fprintf(stderr,"Could not write claro.lock\n"); return 1; } printf("Unknown package command. Try: claro package init\n"); return 1; }
|
||||
static int print_ide_info(void){ printf("{\n"); printf(" \"language\": \"Claro\",\n"); printf(" \"version\": \"v1.17.26\",\n"); printf(" \"keywords\": [\"SAY\",\"ASK\",\"SET\",\"IF\",\"ELSE\",\"END\",\"REPEAT\",\"TEACH\",\"DO\",\"CLASS\",\"NEW\",\"START TASK\",\"HTTP GET\",\"OPEN WINDOW\"],\n"); printf(" \"types\": [\"NUMBER\",\"TEXT\",\"YESNO\",\"LIST\",\"MAP\",\"OBJECT\",\"ANY\"]\n"); printf("}\n"); return 0; }
|
||||
static int package_doctor(void){ int ok=1; char *mainfile; char *txt; printf("%s\n",CLARO_VERSION); printf("Package/project doctor:\n"); printf(" %s claro.project\n",file_exists_simple("claro.project")?"OK":"MISSING"); if(!file_exists_simple("claro.project")) ok=0; mainfile=project_value("main"); if(mainfile&&*mainfile){ printf(" %s main script: %s\n",file_exists_simple(mainfile)?"OK":"MISSING",mainfile); if(!file_exists_simple(mainfile)) ok=0; } else { printf(" MISSING main setting\n"); ok=0; } printf(" %s packages folder\n",path_exists_simple("packages")?"OK":"MISSING"); if(!path_exists_simple("packages")) ok=0; printf(" %s claro.lock\n",file_exists_simple("claro.lock")?"OK":"MISSING"); if(!file_exists_simple("claro.lock")) ok=0; txt=read_file_text("claro.project"); if(txt){ char *p=txt; while(*p){ char *line=p; char save; while(*p&&*p!='\n'&&*p!='\r') p++; save=*p; *p=0; { char *t=trim_inplace(line); if(strnicmp2(t,"package:",8)==0){ char *pkg=trim_inplace(t+8); if(*pkg){ char meta[512], *mt, sum[32]; snprintf(meta,sizeof(meta),"packages/%s/claro.package",pkg); mt=read_file_text(meta); if(mt&&strstr(mt,"manifest-version: 1")&&strstr(mt,"checksum:")){ printf(" OK package manifest: %s\n",pkg); package_checksum(pkg,sum,sizeof(sum)); if(strstr(mt,sum)) printf(" OK package checksum: %s\n",pkg); else { printf(" BAD package checksum: %s\n",pkg); ok=0; } } else { printf(" MISSING package manifest: %s\n",pkg); ok=0; } free(mt); } } } if(save) p++; while(*p=='\n'||*p=='\r') p++; } free(txt); } free(mainfile); printf("%s\n",ok?"Package/project files look ready.":"Package/project files need attention."); return ok?0:1; }
|
||||
static int run_package_cmd(int argc,char **argv,int arg){ if(arg>=argc){ printf("Package commands:\n claro package init\n claro package add NAME\n claro package remove NAME\n claro package list\n claro package doctor\n claro package lock\n"); return 0; } if(strcmp(argv[arg],"init")==0){ ensure_project_file(); make_folder("packages"); write_package_lock(); printf("Package project ready: claro.project, claro.lock, packages/\n"); return 0; } if(strcmp(argv[arg],"add")==0&&arg+1<argc){ const char *name=argv[arg+1]; int already; if(!package_name_safe(name)){ fprintf(stderr,"Package names may use only letters, numbers, dash, and underscore.\n"); return 1; } ensure_project_file(); make_folder("packages"); already=package_has_name(name); if(!append_package_to_project(name)) return 1; create_package_folder(name); write_package_lock(); if(!already) printf("Added package: %s\n",name); return 0; } if(strcmp(argv[arg],"remove")==0&&arg+1<argc){ const char *name=argv[arg+1]; if(!package_name_safe(name)){ fprintf(stderr,"Package names may use only letters, numbers, dash, and underscore.\n"); return 1; } if(remove_package_from_project(name)) printf("Removed package from project: %s\n",name); else printf("Package was not listed: %s\n",name); return 0; } if(strcmp(argv[arg],"list")==0) return list_project_packages(); if(strcmp(argv[arg],"doctor")==0) return package_doctor(); if(strcmp(argv[arg],"lock")==0||strcmp(argv[arg],"update")==0){ ensure_project_file(); make_folder("packages"); if(write_package_lock()){ printf("Updated claro.lock\n"); return 0; } fprintf(stderr,"Could not write claro.lock\n"); return 1; } printf("Unknown package command. Try: claro package init\n"); return 1; }
|
||||
static int print_ide_info(void){
|
||||
printf("{\n");
|
||||
printf(" \"language\": \"Claro\",\n");
|
||||
printf(" \"version\": \"v1.18.26\",\n");
|
||||
printf(" \"file_extensions\": [\".claro\"],\n");
|
||||
printf(" \"keywords\": [\"SAY\",\"ASK\",\"SET\",\"IF\",\"ELSE\",\"ENDIF\",\"END\",\"REPEAT\",\"UNTIL\",\"TEACH\",\"LEARNED\",\"DO\",\"RETURN\",\"CLASS\",\"HAS\",\"NEW\",\"IMPORT\",\"TRY\",\"CATCH\",\"ENDTRY\",\"START TASK\",\"YIELD\",\"WAIT TASK\",\"TASK STATUS\",\"HTTP CHECK\",\"HTTP GET\",\"HTTP SAVE\",\"OPEN WINDOW\"],\n");
|
||||
printf(" \"types\": [\"NUMBER\",\"TEXT\",\"YESNO\",\"LIST\",\"LIST OF TEXT\",\"LIST OF NUMBER\",\"LIST OF YESNO\",\"MAP\",\"MAP OF TEXT\",\"MAP OF NUMBER\",\"MAP OF YESNO\",\"OBJECT\",\"ANY\"],\n");
|
||||
printf(" \"commands\": [\n");
|
||||
printf(" {\"name\": \"run\", \"usage\": \"claro run\", \"description\": \"Run main.claro or the project main script\"},\n");
|
||||
printf(" {\"name\": \"check\", \"usage\": \"claro check file.claro\", \"description\": \"Check beginner syntax and block mistakes\"},\n");
|
||||
printf(" {\"name\": \"typecheck\", \"usage\": \"claro typecheck file.claro\", \"description\": \"Check static types before running\"},\n");
|
||||
printf(" {\"name\": \"fmt\", \"usage\": \"claro fmt file.claro\", \"description\": \"Print a formatted version of a script\"},\n");
|
||||
printf(" {\"name\": \"test\", \"usage\": \"claro test\", \"description\": \"Run golden tests\"}\n");
|
||||
printf(" ],\n");
|
||||
printf(" \"snippets\": [\n");
|
||||
printf(" {\"name\": \"hello\", \"prefix\": \"say\", \"body\": \"SAY \\\"Hello!\\\"\"},\n");
|
||||
printf(" {\"name\": \"if_else\", \"prefix\": \"if\", \"body\": \"IF condition\\n SAY \\\"Yes\\\"\\nELSE\\n SAY \\\"No\\\"\\nENDIF\"},\n");
|
||||
printf(" {\"name\": \"function\", \"prefix\": \"teach\", \"body\": \"TEACH name item\\n SAY item\\nLEARNED\"},\n");
|
||||
printf(" {\"name\": \"typed_list\", \"prefix\": \"listof\", \"body\": \"SET names AS LIST OF TEXT TO LIST\\nADD \\\"Ada\\\" TO names\"},\n");
|
||||
printf(" {\"name\": \"task\", \"prefix\": \"task\", \"body\": \"START TASK helloTask\\n SAY \\\"Inside task\\\"\\n YIELD\\nENDTASK\\nTASK STATUS helloTask AS status\\nSAY status\\nWAIT TASK helloTask\"}\n");
|
||||
printf(" ],\n");
|
||||
printf(" \"diagnostics\": [\n");
|
||||
printf(" {\"source\": \"claro check\", \"format\": \"path:line: message\", \"description\": \"Syntax and block-structure diagnostics\"},\n");
|
||||
printf(" {\"source\": \"claro typecheck\", \"format\": \"path:line: message\", \"description\": \"Static type diagnostics for variables and containers\"}\n");
|
||||
printf(" ]\n");
|
||||
printf("}\n");
|
||||
return 0;
|
||||
}
|
||||
static void print_help(void){
|
||||
printf("%s\n",CLARO_VERSION);
|
||||
printf("Usage:\n");
|
||||
@@ -560,6 +597,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"); if(typecheck_file("tests/typecheck_bad.claro")==0) fails++; printf("%s\n",fails?"Validation found problems.":"Validation passed. Claro v1.17.26 networking reliability is 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"); if(typecheck_file("tests/typecheck_bad.claro")==0) fails++; if(typecheck_file("tests/typecheck_container_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; } }
|
||||
|
||||
Reference in New Issue
Block a user