(*********************************************************************************)
(*                Higlo                                                          *)
(*                                                                               *)
(*    Copyright (C) 2014-2021 Institut National de Recherche en Informatique     *)
(*    et en Automatique. All rights reserved.                                    *)
(*                                                                               *)
(*    This program is free software; you can redistribute it and/or modify       *)
(*    it under the terms of the GNU Lesser General Public License version        *)
(*    3 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              *)
(*    GNU Library General Public License for more details.                       *)
(*                                                                               *)
(*    You should have received a copy of the GNU Lesser General Public           *)
(*    License along with this program; if not, write to the Free Software        *)
(*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA                   *)
(*    02111-1307  USA                                                            *)
(*                                                                               *)
(*    Contact: Maxence.Guesdon@inria.fr                                          *)
(*                                                                               *)
(*                                                                               *)
(*********************************************************************************)

open Lang

let lexeme lb = Sedlexing.(Utf8.lexeme lb, lexeme_length lb);;
let sedlexeme = Sedlexing.Utf8.lexeme;;

let echar = [%sedlex.regexp ? 't' | 'b' | 'n' | 'r' | 'f' | '\\' | '"' | '\'']

let escaped_char = [%sedlex.regexp? '\\', echar]
let string = [%sedlex.regexp? '"', Star( Compl(0x22) | escaped_char ), '"']
let char = [%sedlex.regexp? "'",  ( Compl(0x27) | escaped_char ), "'"]

let space = [%sedlex.regexp? Plus(' ' | '\n' | '\t' | '\r')]

let comment = [%sedlex.regexp? "/*", Star(Compl(0x2A) | ('*',Compl('/'))), "*/"]

let keyword = [%sedlex.regexp? "digraph" |"edge" |"graph" |"subgraph"]

(* split attribute list because of sedlex bug:
  https://github.com/ocaml-community/sedlex/issues/97 *)
let attribute = [%sedlex.regexp?
    "arrowhead" | "arrowsize" | "arrowtail" | "bgcolor" | "center" | "color" | "constraint"]
let attribute2 = [%sedlex.regexp?
    "decorateP" | "dir" | "distortion" | "fillcolor" | "fontcolor" | "fontname" | "fontsize"]
let attribute3 = [%sedlex.regexp?
    "headclip" | "headlabel" | "height" | "labelangle" | "labeldistance" | "labelfontcolor"
  | "labelfontname" | "labelfontsize" | "label" | "layers" | "layer" | "margin" | "mclimit" ]
let attribute4 = [%sedlex.regexp?
    "minlen" | "name" | "nodesep" | "nslimit" | "ordering" | "orientation" | "pagedir" | "page"
  | "peripheries" | "port_label_distance" | "rankdir" | "ranksep" | "rank" | "ratio" | "regular"]
let attribute5 = [%sedlex.regexp?
    "rotate" | "samehead" | "sametail" | "shapefile" | "shape" | "sides" | "size" | "skew"
  | "style" | "tailclip" | "taillabel" | "URL" | "weight" | "width"]

let symbol = [%sedlex.regexp ? "--" | "->"]

let main lexbuf = match%sedlex lexbuf with
| space -> [Text (lexeme lexbuf)]
| keyword -> [Keyword (0, lexeme lexbuf)]
| attribute -> [Keyword (1, lexeme lexbuf)]
| attribute2 -> [Keyword (1, lexeme lexbuf)]
| attribute3 -> [Keyword (1, lexeme lexbuf)]
| attribute4 -> [Keyword (1, lexeme lexbuf)]
| attribute5 -> [Keyword (1, lexeme lexbuf)]
| string -> [String (lexeme lexbuf)]
| char -> [String (lexeme lexbuf)]
| comment -> [Bcomment (lexeme lexbuf)]
| symbol -> [Keyword(2,lexeme lexbuf)]
| any -> [Text (lexeme lexbuf)]
| eof -> []
| _ -> failwith "Invalid state"
;;

let () = Lang.register_lang "dot" main;;
