123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188(* packaging of annotated sexp functions *)moduleList=structletitert~f=List.iterftletmapt~f=List.rev(List.rev_mapft)endincludeType_with_layouttypepos=Src_pos.Relative.t={row:int;col:int}letsexp_of_pos=Src_pos.Relative.sexp_of_tmoduleLexer=structletmain=Lexer.main_with_layoutendmoduleParser=Parser_with_layoutmoduleRender=structmoduleRel_pos=Src_pos.RelativemoduleAbs_pos=Src_pos.Absolutetypelast_atom={immed_after:Abs_pos.t;unescaped:bool}typestate={mutablerow_shift:Rel_pos.t;mutablecurrent:Abs_pos.t;mutablelast_atom:last_atomoption;mutablelast_comment_row:int}(* the point of [immed_after_last_atom] is to prevent
(A B C) from rendering as (A BBC) after we replace B with BB *)type'at=(char->unit)->state->'aletreturna_putc_st=aletbindm~fputcst=f(mputcst)putcstletrunputcm=mputc{row_shift=Rel_pos.zero;current=Abs_pos.origin;last_atom=None;last_comment_row=0(* before the file starts *)};;letemit_charputcstc=let{Abs_pos.col;row}=st.currentinputcc;ifc='\n'thenst.current<-{Abs_pos.row=1+row;col=1}elsest.current<-{Abs_pos.row;col=1+col};;letemit_stringputcststr=letn=String.lengthstrinfori=0ton-1doemit_charputcststr.[i]done;;letemit_charsputcstc~n=emit_stringputcst(String.makenc)letadvanceputc~anchorst~by:delta~unescaped_atom~line_comment=letnew_pos=Abs_pos.add(Abs_pos.addanchordelta)st.row_shiftinletneed_to_leave_room_between_two_unescaped_atoms_lest_they_become_one=unescaped_atom&&matchst.last_atomwith|Some{immed_after;unescaped=prev_unescaped}->new_pos=immed_after&&prev_unescaped|None->falsein(* avoid joining subsequent items into a preceding line comment *)letneed_to_clear_line_comment=new_pos.row=st.last_comment_rowinletneed_to_reposition=(not(Abs_pos.geqnew_posst.current))||need_to_clear_line_comment||need_to_leave_room_between_two_unescaped_atoms_lest_they_become_oneinletrow_delta,new_pos=ifneed_to_repositionthen((* repositioning heuristic: just move to the next fresh row *)letnew_row=1+st.current.Abs_pos.rowinletrow_delta=new_row-new_pos.Abs_pos.rowinrow_delta,{Abs_pos.row=new_row;col=new_pos.Abs_pos.col})else0,new_posin(* advance to new_pos by emitting whitespace *)ifnew_pos.Abs_pos.row>st.current.Abs_pos.rowthen(letn=new_pos.Abs_pos.row-st.current.Abs_pos.rowinemit_charsputcst'\n'~n);ifnew_pos.Abs_pos.col>st.current.Abs_pos.colthen(letn=new_pos.Abs_pos.col-st.current.Abs_pos.colinemit_charsputcst' '~n);assert(new_pos=st.current);ifline_commentthenst.last_comment_row<-st.current.row;st.row_shift<-{st.row_shiftwithRel_pos.row=st.row_shift.Rel_pos.row+row_delta};;letrecrender_tputc~anchor(st:state)t=matchtwith|Atom(delta,text,fmt_text)->letfmt_text=matchfmt_textwith|None|Some""->Pre_sexp.mach_maybe_esc_strtext|Sometext->textinletunescaped=fmt_text.[0]<>'"'inadvanceputcst~by:delta~anchor~unescaped_atom:unescaped~line_comment:false;emit_stringputcstfmt_text;st.last_atom<-Some{immed_after=st.current;unescaped}|List(start_delta,tocs,end_delta)->advanceputcst~by:start_delta~anchor~unescaped_atom:false~line_comment:false;letchild_anchor=Abs_pos.subst.currentst.row_shiftinemit_charputcst'(';List.itertocs~f:(funtoc->render_tocputc~anchor:child_anchorsttoc);advanceputcst~by:end_delta~anchor~unescaped_atom:false~line_comment:false;emit_charputcst')';()andrender_tocputc~anchorst=function|Sexpt->render_tputc~anchorstt|Commentc->render_cputc~anchorstcandrender_cputc~anchorst=function|Plain_comment(delta,text)->letline_comment=String.lengthtext>0&&text.[0]=';'inadvanceputcst~by:delta~anchor~unescaped_atom:false~line_comment;emit_stringputcsttext|Sexp_comment(delta,cs,t)->advanceputcst~by:delta~anchor~unescaped_atom:false~line_comment:false;emit_stringputcst"#;";List.itercs~f:(render_cputc~anchorst);render_tputc~anchorstt;;letrenderasexpputcst=render_tocputc~anchor:Abs_pos.originstasexpletsexp=renderendmoduleForget=struct(* In cps to prevent non-tail recursion.
The polymorphism in the signature ensures that each function returns
only through the continuation. *)moduleCps:sigvalforget_t:t->(Type.t->'r)->'rvalforget_toc:t_or_comment->(Type.toption->'r)->'rvalforget_tocs:t_or_commentlist->(Type.tlist->'r)->'rend=structletrecforget_ttk=matchtwith|Atom(_,x,_)->k(Type.Atomx)|List(_,tocs,_)->forget_tocstocs(funxs->k(Type.Listxs))andforget_tocstocsk=matchtocswith|[]->k[]|toc::tocs->forget_toctoc(function|None->forget_tocstocsk|Somex->forget_tocstocs(funxs->k(x::xs)))andforget_toctock=matchtocwith|Comment_->kNone|Sexpt->forget_tt(funx->k(Somex));;endlettx=Cps.forget_tx(funy->y)lett_or_commentx=Cps.forget_tocx(funy->y)lett_or_commentsx=Cps.forget_tocsx(funy->y)end