123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164(* Yoann Padioleau
*
* Copyright (C) 2010 Facebook
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License (GPL)
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* file license.txt for more details.
*)openCommonopenParser_lispopenAst_lispmodulePI=Parse_info(* we don't need a full grammar for lisp code, so we put everything,
* the token type, the helper in parser_ml. No token_helpers_lisp.ml
*)moduleTH=Parser_lisp(*****************************************************************************)(* Prelude *)(*****************************************************************************)(*
* alt:
* - Could reuse the parser in ocamlsexp ? but they just have Atom | Sexp
* and I need to differentiate numbers in the highlighter, and
* also handling quoted, anti-quoted and other lisp special things.
*)(*****************************************************************************)(* Types *)(*****************************************************************************)(* the token list contains also the comment-tokens *)typeprogram_and_tokens=Ast_lisp.programoption*Parser_lisp.tokenlist(*****************************************************************************)(* Lexing only *)(*****************************************************************************)(* could factorize and take the tokenf and visitor_of_infof in argument
* but sometimes copy-paste is ok.
*)lettokens2file=lettoken=Lexer_lisp.tokeninParse_info.tokenize_all_and_adjust_posfiletokenTH.visitor_info_of_tokTH.is_eoflettokensa=Common.profile_code"Parse_lisp.tokens"(fun()->tokens2a)(*****************************************************************************)(* Parser *)(*****************************************************************************)(* simple recursive descent parser *)letrecsexpstoks=matchtokswith|[]->[],[]|[EOF_]->[],[]|(TCParen_|TCBracket_)::_->[],toks|xs->lets,rest=sexpxsinletxs,rest=sexpsrestins::xs,restandsexptoks=matchtokswith|[]->raiseTodo|x::xs->(matchxwith|TComment_|TCommentSpace_|TCommentNewline_->raiseImpossible|TNumberx->Atom(Numberx),xs|TStringx->Atom(Stringx),xs|TIdentx->Atom(Idx),xs|TOParent1->let(xs,rest)=sexpsxsin(matchrestwith|TCParent2::rest->Sexp((t1,xs,t2)),rest|_->raise(PI.Other_error("unclosed parenthesis",t1)))|TOBrackett1->let(xs,rest)=sexpsxsin(matchrestwith|TCBrackett2::rest->Sexp((t1,xs,t2)),rest|_->raise(PI.Other_error("unclosed bracket",t1)))|TCParent|TCBrackett->raise(PI.Other_error("closing bracket/paren without opening one",t))|TQuotet->let(s,rest)=sexpxsinSpecial((Quote,t),s),rest|TBackQuotet->let(s,rest)=sexpxsinSpecial((BackQuote,t),s),rest|TAtt->let(s,rest)=sexpxsinSpecial((At,t),s),rest|TCommat->let(s,rest)=sexpxsinSpecial((Comma,t),s),rest(* hmmm probably unicode *)|TUnknownt->Atom(String(PI.str_of_infot,t)),xs|EOFt->raise(PI.Other_error("unexpected eof",t)))(*****************************************************************************)(* Main entry point *)(*****************************************************************************)letparse2filename=letstat=Parse_info.default_statfilenameinlettoks_orig=tokensfilenameinlettoks=toks_orig|>Common.excludeTH.is_commentinletnblines=Common2.nblinesfilenameinletast=try(matchsexpstokswith|xs,[]->stat.PI.correct<-nblines;Somexs|_,x::_xs->raise(PI.Other_error("trailing constructs",(TH.info_of_tokx))))with|PI.Other_error(s,info)->pr2(spf"Parse error: %s, {%s} at %s"s(PI.str_of_infoinfo)(PI.string_of_infoinfo));stat.PI.bad<-nblines;None|exn->raiseexnin(ast,toks_orig),statletparsea=Common.profile_code"Parse_lisp.parse"(fun()->parse2a)letparse_programfile=let(ast,_toks),_stat=parsefileinCommon2.someast