123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352(** CSS lexer.
* Reference:
* https://www.w3.org/TR/css-syntax-3/
* https://github.com/yahoo/css-js/blob/master/src/l/css.3.l *)moduleSedlexing=Lex_bufferexceptionLexingErrorof(Lexing.position*string)(** Signals a lexing error at the provided source location. *)exceptionParseErrorof(Menhir_parser.token*Lexing.position*Lexing.position)(** Signals a parsing error at the provided token and its start and end
* locations. *)exceptionGrammarErrorof(string*Location.t)(** Signals a grammar error at the provided location. *)letposition_to_stringpos=Printf.sprintf"[%d,%d+%d]"pos.Lexing.pos_lnumpos.Lexing.pos_bol(pos.Lexing.pos_cnum-pos.Lexing.pos_bol)letlocation_to_stringloc=Printf.sprintf"%s..%s"(position_to_stringloc.Location.loc_start)(position_to_stringloc.Location.loc_end)letdimension_to_string=function|Types.Length->"length"|Angle->"angle"|Time->"time"|Frequency->"frequency"lettoken_to_string=function|Menhir_parser.EOF->"EOF"|LEFT_BRACE->"{"|RIGHT_BRACE->"}"|LEFT_PAREN->"("|RIGHT_PAREN->")"|LEFT_BRACKET->"["|RIGHT_BRACKET->"]"|COLON->":"|DOT->"."(* Whitespaces are detected only in selectors, before ":", ".", and "#", to
* disambiguate between "p :first-child" and "p:first-child", these
* whitespaces are replaced with "*" *)|WHITESPACE->"*"|SEMI_COLON->";"|PERCENTAGE->"%"|IMPORTANT->"!important"|IDENTs->"IDENT("^s^")"|STRINGs->"STRING("^s^")"|URIs->"URI("^s^")"|OPERATORs->"OPERATOR("^s^")"|DELIMs->"DELIM("^s^")"|NESTED_AT_RULEs->"NESTED_AT_RULE("^s^")"|AT_RULE_WITHOUT_BODYs->"AT_RULE_WITHOUT_BODY("^s^")"|AT_RULEs->"AT_RULE("^s^")"|FUNCTIONs->"FUNCTION("^s^")"|HASHs->"HASH("^s^")"|NUMBERs->"NUMBER("^s^")"|UNICODE_RANGEs->"UNICODE_RANGE("^s^")"|FLOAT_DIMENSION(n,s,d)->"FLOAT_DIMENSION("^n^", "^s^", "^dimension_to_stringd^")"|DIMENSION(n,d)->"DIMENSION("^n^", "^d^")"let()=Location.register_error_of_exn(function|LexingError(pos,msg)->letloc=Lex_buffer.make_loc_and_fixposposinSome(Location.error~locmsg)|ParseError(token,start_pos,end_pos)->letloc=Lex_buffer.make_loc_and_fixstart_posend_posinletmsg=Printf.sprintf"Parse error while reading token '%s'"(token_to_stringtoken)inSome(Location.error~locmsg)|GrammarError(msg,loc)->Some(Location.error~locmsg)|_->None)(* Regexes *)letnewline=[%sedlex.regexp?'\n'|"\r\n"|'\r'|'\012']letwhite_space=[%sedlex.regexp?" "|'\t'|newline]letws=[%sedlex.regexp?Starwhite_space]lethex_digit=[%sedlex.regexp?'0'..'9'|'a'..'f'|'A'..'F']letdigit=[%sedlex.regexp?'0'..'9']letnon_ascii=[%sedlex.regexp?'\160'..'\255']letup_to_6_hex_digits=[%sedlex.regexp?Rep(hex_digit,1..6)]letunicode=[%sedlex.regexp?'\\',up_to_6_hex_digits,Optwhite_space]letunicode_range=[%sedlex.regexp?(Rep((hex_digit|'?'),1..6)|up_to_6_hex_digits,'-',up_to_6_hex_digits)]letescape=[%sedlex.regexp?unicode|'\\',Compl('\r'|'\n'|'\012'|hex_digit)]letident_start=[%sedlex.regexp?'_'|'a'..'z'|'A'..'Z'|non_ascii|escape]letident_char=[%sedlex.regexp?'_'|'a'..'z'|'A'..'Z'|'0'..'9'|'-'|non_ascii|escape]letident=[%sedlex.regexp?(Opt'-',ident_start|'-','-'),Starident_char]letstring_quote=[%sedlex.regexp?'"',Star(Compl('\n'|'\r'|'\012'|'"')|'\\',newline|escape),'"']letstring_apos=[%sedlex.regexp?('\'',Star(Compl('\n'|'\r'|'\012'|'\'')|'\\',newline|escape),'\'')]letstring=[%sedlex.regexp?string_quote|string_apos]letname=[%sedlex.regexp?Plusident_char]letnumber=[%sedlex.regexp?((Opt('+'|'-'),Plusdigit,Opt('.',Plusdigit),Opt(('e'|'E'),('+'|'-'),Plusdigit))|(Opt('+'|'-'),'.',Plusdigit,Opt(('e'|'E'),('+'|'-'),Plusdigit)))]letnon_printable=[%sedlex.regexp?'\x00'..'\x08'|'\x0B'|'\x0E'..'\x1F'|'\x7F']leturl_unquoted=[%sedlex.regexp?Star(Compl('"'|'\''|'('|')'|'\\'|non_printable)|escape)]leturl=[%sedlex.regexp?url_unquoted|string]letoperator=[%sedlex.regexp?"~="|"|="|"^="|"$="|"*="|"||"]letat_rule=[%sedlex.regexp?"@",ident]letat_rule_without_body=[%sedlex.regexp?"@",("charset"|"import"|"namespace")]letvendor_prefix=[%sedlex.regexp?"-webkit-"|"-moz-"|"-o-"|"-ms-"]letnested_at_rule=[%sedlex.regexp?("@",("document"|"keyframes"|vendor_prefix,"keyframes"|"media"|"supports"|"scope"))]let_a=[%sedlex.regexp?'A'|'a']let_b=[%sedlex.regexp?'B'|'b']let_c=[%sedlex.regexp?'C'|'c']let_d=[%sedlex.regexp?'D'|'d']let_e=[%sedlex.regexp?'e'|'E']let_f=[%sedlex.regexp?'F'|'f']let_g=[%sedlex.regexp?'G'|'g']let_h=[%sedlex.regexp?'H'|'h']let_i=[%sedlex.regexp?'I'|'i']let_j=[%sedlex.regexp?'J'|'j']let_k=[%sedlex.regexp?'K'|'k']let_l=[%sedlex.regexp?'L'|'l']let_m=[%sedlex.regexp?'M'|'m']let_n=[%sedlex.regexp?'N'|'n']let_o=[%sedlex.regexp?'O'|'o']let_p=[%sedlex.regexp?'P'|'p']let_q=[%sedlex.regexp?'Q'|'q']let_r=[%sedlex.regexp?'R'|'r']let_s=[%sedlex.regexp?'S'|'s']let_t=[%sedlex.regexp?'T'|'t']let_u=[%sedlex.regexp?'U'|'u']let_v=[%sedlex.regexp?'V'|'v']let_w=[%sedlex.regexp?'W'|'w']let_x=[%sedlex.regexp?'X'|'x']let_y=[%sedlex.regexp?'Y'|'y']let_z=[%sedlex.regexp?'Z'|'z']letimportant=[%sedlex.regexp?"!",ws,_i,_m,_p,_o,_r,_t,_a,_n,_t]letlength=[%sedlex.regexp?(_c,_a,_p|_c,_h|_e,_m|_e,_x|_i,_c|_l,_h|_r,_e,_m|_r,_l,_h|_v,_h|_v,_w|_v,_i|_v,_b|_v,_m,_i,_n|_v,_m,_a,_x|_c,_m|_m,_m|_q|_i,_n|_p,_c|_p,_t|_p,_x|_f,_r)]letangle=[%sedlex.regexp?_d,_e,_g|_g,_r,_a,_d|_r,_a,_d|_t,_u,_r,_n]lettime=[%sedlex.regexp?_s|_m,_s]letfrequency=[%sedlex.regexp?_h,_z|_k,_h,_z](* Returns true if white spaces were discarded *)letdiscard_comments_and_white_spacesbuf=letrecdiscard_white_spacesbufspaces_detected=match%sedlexbufwith|Pluswhite_space->discard_white_spacesbuftrue|"/*"->discard_commentsbufspaces_detected|_->spaces_detectedanddiscard_commentsbufspaces_detected=match%sedlexbufwith|eof->raise(LexingError(buf.Lex_buffer.pos,"Unterminated comment at EOF"))|"*/"->discard_white_spacesbufspaces_detected|any->discard_commentsbufspaces_detected|_->assertfalseindiscard_white_spacesbuffalseletrecget_next_tokensbufspaces_detected=letopenMenhir_parserinmatch%sedlexbufwith|eof->[EOF]|';'->[SEMI_COLON]|'}'->[RIGHT_BRACE]|'{'->[LEFT_BRACE]|':'->ifspaces_detectedthen[WHITESPACE;COLON]else[COLON]|'.'->ifspaces_detectedthen[WHITESPACE;DOT]else[DOT]|'('->[LEFT_PAREN]|')'->[RIGHT_PAREN]|'['->[LEFT_BRACKET]|']'->[RIGHT_BRACKET]|'%'->[PERCENTAGE]|operator->[OPERATOR(Lex_buffer.latin1buf)]|string->[STRING(Lex_buffer.latin1~skip:1~drop:1buf)]|"url("->[get_url""buf]|important->[IMPORTANT]|nested_at_rule->[NESTED_AT_RULE(Lex_buffer.latin1~skip:1buf)]|at_rule_without_body->[AT_RULE_WITHOUT_BODY(Lex_buffer.latin1~skip:1buf)]|at_rule->[AT_RULE(Lex_buffer.latin1~skip:1buf)](* NOTE: should be placed above ident, otherwise pattern with
* '-[0-9a-z]{1,6}' cannot be matched *)|_u,'+',unicode_range->[UNICODE_RANGE(Lex_buffer.latin1buf)]|ident,'('->[FUNCTION(Lex_buffer.latin1~drop:1buf)]|ident->[IDENT(Lex_buffer.latin1buf)]|'#',name->ifspaces_detectedthen[WHITESPACE;HASH(Lex_buffer.latin1~skip:1buf)]else[HASH(Lex_buffer.latin1~skip:1buf)]|number->[get_dimension(Lex_buffer.latin1buf)buf]|any->[DELIM(Lex_buffer.latin1buf)]|_->assertfalseandget_dimensionnbuf=match%sedlexbufwith|length->FLOAT_DIMENSION(n,Lex_buffer.latin1buf,Types.Length)|angle->FLOAT_DIMENSION(n,Lex_buffer.latin1buf,Types.Angle)|time->FLOAT_DIMENSION(n,Lex_buffer.latin1buf,Types.Time)|frequency->FLOAT_DIMENSION(n,Lex_buffer.latin1buf,Types.Frequency)|ident->DIMENSION(n,Lex_buffer.latin1buf)|_->NUMBERnandget_urlurlbuf=match%sedlexbufwith|ws->get_urlurlbuf|url->get_url(Lex_buffer.latin1buf)buf|")"->URIurl|eof->raise(LexingError(buf.Lex_buffer.pos,"Incomplete URI"))|any->raise(LexingError(buf.Lex_buffer.pos,"Unexpected token: "^Lex_buffer.latin1buf^" parsing an URI"))|_->assertfalselettoken_queue=Queue.create()letqueue_next_tokens_with_locationbuf=letspaces_detected=discard_comments_and_white_spacesbufinletloc_start=Lex_buffer.next_locbufinlettokens=get_next_tokensbufspaces_detectedinletloc_end=Lex_buffer.next_locbufinList.iter(funt->Queue.add(t,loc_start,loc_end)token_queue)tokensletparsebufp=letlast_token=ref(Menhir_parser.EOF,Lexing.dummy_pos,Lexing.dummy_pos)inletnext_token()=ifQueue.is_emptytoken_queuethenqueue_next_tokens_with_locationbuf;last_token:=Queue.taketoken_queue;!last_tokenintryMenhirLib.Convert.Simplified.traditional2revisedpnext_tokenwith|LexingError_ase->raisee|_->raise(ParseError!last_token)letparse_string?container_lnum?possp=(matchcontainer_lnumwith|None->()|Somelnum->Lex_buffer.container_lnum_ref:=lnum);parse(Lex_buffer.of_ascii_string?poss)p