mte/unikernel/duniverse/dune_/vendor/opam-file-format/opamLexer.mll

199 lines
6.1 KiB
OCaml
Raw Normal View History

2025-11-11 02:07:51 +01:00
(**************************************************************************)
(* *)
(* Copyright 2012-2019 OCamlPro *)
(* Copyright 2012 INRIA *)
(* *)
(* All rights reserved. This file is distributed under the terms of the *)
(* GNU Lesser General Public License version 2.1, with the special *)
(* exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
{
open OpamParserTypes
open OpamBaseParser
exception Error of string
let newline lexbuf = Lexing.new_line lexbuf
let error fmt =
Printf.ksprintf (fun msg -> raise (Error msg)) fmt
let relop = function
| "=" -> `Eq
| "!=" -> `Neq
| ">=" -> `Geq
| ">" -> `Gt
| "<=" -> `Leq
| "<" -> `Lt
| "~" -> `Geq
| x -> error "%S is not a valid comparison operator" x
let logop = function
| "&" -> `And
| "|" -> `Or
| x -> error "%S is not a valid logical operator" x
let pfxop = function
| "!" -> `Not
| "?" -> `Defined
| x -> error "%S is not a valid prefix operator" x
let env_update_op : string -> env_update_op = function
| "=" -> Eq
| "+=" -> PlusEq
| "=+" -> EqPlus
| "=+=" -> EqPlusEq
| ":=" -> ColonEq
| "=:" -> EqColon
| x -> error "%S is not a valid environment update operator" x
module FullPos = struct
let relop = relop
let logop = logop
let pfxop = pfxop
let env_update_op = env_update_op
end
let char_for_backslash = function
| 'n' -> '\010'
| 'r' -> '\013'
| 'b' -> '\008'
| 't' -> '\009'
| c -> c
let char_for_decimal_code lexbuf i =
let c = 100 * (Char.code(Lexing.lexeme_char lexbuf i) - 48) +
10 * (Char.code(Lexing.lexeme_char lexbuf (i+1)) - 48) +
(Char.code(Lexing.lexeme_char lexbuf (i+2)) - 48) in
if (c < 0 || c > 255) then error "illegal escape sequence" ;
Char.chr c
let char_for_hexadecimal_code lexbuf i =
let d1 = Char.code (Lexing.lexeme_char lexbuf i) in
let val1 = if d1 >= 97 then d1 - 87
else if d1 >= 65 then d1 - 55
else d1 - 48 in
let d2 = Char.code (Lexing.lexeme_char lexbuf (i+1)) in
let val2 = if d2 >= 97 then d2 - 87
else if d2 >= 65 then d2 - 55
else d2 - 48 in
Char.chr (val1 * 16 + val2)
(* Some hash-consing for strings *)
module HS = Weak.Make(struct
include struct
[@@@ocaml.warning "-32"]
let hash = Hashtbl.hash
end
include String
end)
let hm = HS.create 317
let buf = Buffer.create 64
let buffer_rule r lb =
let pos = lb.Lexing.lex_start_p in
Buffer.clear buf;
r buf lb;
(* buffer start position, instead of last lexem position *)
lb.Lexing.lex_start_p <- pos;
let contents = Buffer.contents buf in
HS.merge hm contents
}
let eol = '\r'? '\n'
let space = [' ' '\t']
let alpha = ['a'-'z' 'A'-'Z']
let digit = ['0'-'9']
let ichar = alpha | digit | ['_' '-']
let id = ichar* alpha ichar*
let ident = (id | '_') ('+' (id | '_'))* (':' id)?
let relop = ('!'? '=' | [ '<' '>' ] '='? | '~')
let pfxop = '!' | '?'
let envop_char = [ '+' ':' ]
let envop = (envop_char '=' | '=' envop_char '='?)
let int = ('-'? ['0'-'9' '_']+)
rule token = parse
| space { token lexbuf }
| eol { newline lexbuf; token lexbuf }
| ":" { COLON }
| "{" { LBRACE }
| "}" { RBRACE }
| "[" { LBRACKET }
| "]" { RBRACKET }
| "(" { LPAR }
| ")" { RPAR }
| '\"' { STRING (buffer_rule string lexbuf) }
| "\"\"\"" { STRING (buffer_rule string_triple lexbuf) }
| "(*" { comment 1 lexbuf; token lexbuf }
| '#' [^'\n']*
{ token lexbuf }
| "true" { BOOL true }
| "false"{ BOOL false }
| int { INT (int_of_string (Lexing.lexeme lexbuf)) }
| ident { IDENT (HS.merge hm (Lexing.lexeme lexbuf)) }
| relop { RELOP (FullPos.relop (Lexing.lexeme lexbuf)) }
| '&' { AND }
| '|' { OR }
| pfxop { PFXOP (FullPos.pfxop (Lexing.lexeme lexbuf)) }
| envop { ENVOP (FullPos.env_update_op (Lexing.lexeme lexbuf)) }
| eof { EOF }
(* OpamBaseParser can't directly access OpamLexer.Error so it uses these
constants (which would parse that way) to extract the exception values.
*)
| "opam-version: \"2.1\"\nopam-version: \"z\"" eof
{ error "opam-version cannot be repeated" }
| "version: \"42\"\nopam-version: \"2.1\"" eof
{ error "opam-version must be the first non-comment line" }
| _ { let token = Lexing.lexeme lexbuf in
error "'%s' is not a valid token" token }
and string b = parse
| '\"' { () }
| [^ '\\' '"' '\r' '\n']+ as s { Buffer.add_string b s; string b lexbuf }
| eol { newline lexbuf ;
Buffer.add_char b '\n' ; string b lexbuf }
| '\\' { (match escape lexbuf with
| Some c -> Buffer.add_char b c
| None -> ());
string b lexbuf }
| _ as c { Buffer.add_char b c ; string b lexbuf }
| eof { error "unterminated string" }
and string_triple b = parse
| "\"\"\"" { () }
| [^ '\\' '"' '\r' '\n']+ as s { Buffer.add_string b s; string_triple b lexbuf }
| eol { newline lexbuf ;
Buffer.add_char b '\n' ; string_triple b lexbuf }
| '\\' { (match escape lexbuf with
| Some c -> Buffer.add_char b c
| None -> ());
string_triple b lexbuf }
| _ as c { Buffer.add_char b c ; string_triple b lexbuf }
| eof { error "unterminated string" }
and escape = parse
| eol space *
{ newline lexbuf; None }
| ['\\' '\"' ''' 'n' 'r' 't' 'b' ' '] as c
{ Some (char_for_backslash c) }
| digit digit digit
{ Some (char_for_decimal_code lexbuf 0) }
| 'x' ['0'-'9''a'-'f''A'-'F'] ['0'-'9''a'-'f''A'-'F']
{ Some (char_for_hexadecimal_code lexbuf 1) }
| "" { error "illegal escape sequence" }
and comment n = parse
| "*)" { if n > 1 then comment (n-1) lexbuf }
| "(*" { comment (n+1)lexbuf }
| eof { error "unterminated comment" }
| '\n' { newline lexbuf; comment n lexbuf }
| _ { comment n lexbuf }