#define _GNU_SOURCE //asprintf #include #include #include #include #include "ast.h" #include "util.h" void ast_free(AST *ast){ assert(ast); switch(ast->type){ case AST_LIST: assert(ast->li.len>=0); for(int i=0;ili.len;i++){ assert(ast->li.nodes[i]); ast_free(ast->li.nodes[i]); } break; case AST_LAMBDA: assert(ast->la.cfunc||ast->la.body); if(ast->la.body)ast_free(ast->la.body); break; case AST_LAMBDAARG: break; case AST_WORD: assert(ast->wo.word); free(ast->wo.word); break; case AST_STRING: assert(ast->st.str); free(ast->st.str); break; case AST_NUMBER: case AST_SYMBOL: break; case AST_QUOTED: assert(ast->qu.ast); ast_free(ast->qu.ast); break; default: assert(false); } free(ast); } AST* ast_copy(const AST *ast){ assert(ast); switch(ast->type){ case AST_LIST:{ assert(ast->li.len>=0); assert(ast->li.nodes); AST **nodes=malloc(ast->li.len,AST*); for(int i=0;ili.len;i++)nodes[i]=ast_copy(ast->li.nodes[i]); return ast_list(ast->li.len,nodes); } case AST_LAMBDA: return ast_lambda(ast->la.cfunc,ast->la.body?ast_copy(ast->la.body):NULL); case AST_LAMBDAARG: return ast_lambdaarg(ast->ar.idx); case AST_WORD: assert(ast->wo.word); return ast_word(copystring(ast->wo.word)); case AST_NUMBER: return ast_number(ast->nu.num); case AST_STRING: return ast_string(copybufasstring(ast->st.str,ast->st.len),ast->st.len); case AST_SYMBOL:{ assert(ast->sy.name); AST *sym=ast_symbol(ast->sy.name); sym->sy.symid=ast->sy.symid; return sym; } case AST_QUOTED: return ast_quoted(ast_copy(ast->qu.ast)); default: assert(false); } } typedef struct Buffer{ char *buf; int sz,len; } Buffer; static Buffer buf_make(int capacity){ assert(capacity>0); Buffer buf={malloc(capacity,char),capacity,0}; buf.buf[0]='\0'; return buf; } static void buf_append(Buffer *buf,const char *str,int len){ assert(buf); assert(str); assert(len>=0); if(len==0)return; if(buf->len+len>buf->sz-1){ do buf->sz*=2; while(buf->len+len>buf->sz-1); buf->buf=realloc(buf->buf,buf->sz,char); } memcpy(buf->buf+buf->len,str,len); buf->len+=len; buf->buf[buf->len]='\0'; } static char hexchar(int n){ assert(n>=0&&n<16); if(n<10)return n+'0'; return n-10+'a'; } static void ast_stringify_(const AST *ast,Buffer *buf){ assert(ast); assert(buf); switch(ast->type){ case AST_LIST: buf_append(buf,"(",1); for(int i=0;ili.len;i++){ if(i!=0)buf_append(buf," ",1); ast_stringify_(ast->li.nodes[i],buf); } buf_append(buf,")",1); break; case AST_LAMBDA: buf_append(buf,"[[lambda ",9); if(ast->la.cfunc)buf_append(buf,"cfunc]]",7); else { buf_append(buf,"body ",5); ast_stringify_(ast->la.body,buf); buf_append(buf,"]]",2); } break; case AST_LAMBDAARG:{ buf_append(buf,"[[lambdaArg ",12); char *s; int len=asprintf(&s,"%d",ast->ar.idx); if(!s)outofmem(); buf_append(buf,s,len); free(s); buf_append(buf,"]]",2); break; } case AST_WORD: buf_append(buf,ast->wo.word,strlen(ast->wo.word)); break; case AST_NUMBER:{ char *s; int len=asprintf(&s,"%g",ast->nu.num); if(!s)outofmem(); buf_append(buf,s,len); free(s); break; } case AST_STRING:{ buf_append(buf,"\"",1); const char *str=ast->st.str; for(int i=0;ist.len;i++){ if(str[i]>=32&&str[i]<=126)buf_append(buf,str+i,1); else switch(str[i]){ case '\n': buf_append(buf,"\\n",2); break; case '\t': buf_append(buf,"\\t",2); break; case '\r': buf_append(buf,"\\r",2); break; case '\b': buf_append(buf,"\\b",2); break; case '\a': buf_append(buf,"\\a",2); break; default:{ char hexbuf[4]; hexbuf[0]='\\'; hexbuf[1]='x'; hexbuf[2]=hexchar((unsigned char)str[i]/16); hexbuf[3]=hexchar((unsigned char)str[i]%16); buf_append(buf,hexbuf,4); break; } } } buf_append(buf,"\"",1); break; } case AST_SYMBOL: buf_append(buf,"'",1); buf_append(buf,ast->sy.name,strlen(ast->sy.name)); break; case AST_QUOTED: buf_append(buf,"'",1); ast_stringify_(ast->qu.ast,buf); break; default: assert(false); } } char* ast_stringify(const AST *ast){ assert(ast); Buffer buf=buf_make(32); ast_stringify_(ast,&buf); return buf.buf; } AST* ast_list(int len,AST **nodes){ assert(len>=0); assert(nodes); AST *ast=malloc(1,AST); ast->type=AST_LIST; ast->li.len=len; ast->li.nodes=nodes; return ast; } AST* ast_lambda(lambdafunc_t cfunc,AST *body){ assert(cfunc||body); AST *ast=malloc(1,AST); ast->type=AST_LAMBDA; ast->la.cfunc=cfunc; ast->la.body=body; return ast; } AST* ast_lambdaarg(int idx){ assert(idx>=0); AST *ast=malloc(1,AST); ast->type=AST_LAMBDAARG; ast->ar.idx=idx; return ast; } AST* ast_word(char *word){ assert(word); AST *ast=malloc(1,AST); ast->type=AST_WORD; ast->wo.word=word; return ast; } AST* ast_number(double num){ AST *ast=malloc(1,AST); ast->type=AST_NUMBER; ast->nu.num=num; return ast; } AST* ast_string(char *str,int len){ AST *ast=malloc(1,AST); ast->type=AST_STRING; ast->st.str=str; ast->st.len=len; return ast; } AST* ast_symbol(char *name){ assert(name); AST *ast=malloc(1,AST); ast->type=AST_SYMBOL; ast->sy.name=name; ast->sy.symid=-1; return ast; } AST* ast_quoted(AST *contents){ assert(contents); AST *ast=malloc(1,AST); ast->type=AST_QUOTED; ast->qu.ast=contents; return ast; }