| (* Handler for @custom annotations *) | |
| open Custom | |
| open Annot | |
| open Source | |
| type format' = Custom.custom' | |
| type format = Custom.custom | |
| let name = Utf8.decode "custom" | |
| let place fmt = fmt.it.place | |
| (* Decoding & encoding *) | |
| let decode_content m custom = | |
| let Custom.{name; content; place} = custom.it in | |
| match Custom.handler name with | |
| | Some (module Handler) -> | |
| let module S = | |
| struct | |
| module Handler = Handler | |
| let it = Handler.decode m "" custom | |
| end | |
| in Some (module S : Custom.Section) | |
| | None -> | |
| if !Flags.custom_reject then | |
| raise (Custom.Code (custom.at, | |
| "unknown custom section \"" ^ Utf8.encode name ^ "\"")) | |
| else | |
| None | |
| let decode m _bs custom = | |
| ignore (decode_content m custom); | |
| custom | |
| let encode _m _bs custom = custom | |
| (* Parsing *) | |
| let parse_error at msg = raise (Custom.Syntax (at, msg)) | |
| let rec parse m _bs annots = List.map (parse_annot m) annots | |
| and parse_annot m annot = | |
| let {name = n; items} = annot.it in | |
| assert (n = name); | |
| let cname, items' = parse_name annot.at items in | |
| let place, items'' = parse_place_opt items' in | |
| let content, items''' = parse_content items'' in | |
| parse_end items'''; | |
| let Ast.{types; tags; globals; memories; tables; funcs; start; | |
| datas; elems; imports; exports} = m.it in | |
| let outside x = | |
| if annot.at.left >= x.at.left && annot.at.right <= x.at.right then | |
| parse_error annot.at "misplaced @custom annotation" | |
| in | |
| List.iter outside types; | |
| List.iter outside tags; | |
| List.iter outside globals; | |
| List.iter outside memories; | |
| List.iter outside tables; | |
| List.iter outside funcs; | |
| List.iter outside (Option.to_list start); | |
| List.iter outside elems; | |
| List.iter outside datas; | |
| List.iter outside imports; | |
| List.iter outside exports; | |
| let custom = {name = cname; content; place} @@ annot.at in | |
| ignore (decode_content m custom); | |
| custom | |
| and parse_name at = function | |
| | {it = String s; at} :: items -> | |
| (try Utf8.decode s, items with Utf8.Utf8 -> | |
| parse_error at "@custom annotation: malformed UTF-8 encoding" | |
| ) | |
| | _ -> | |
| parse_error at "@custom annotation: missing section name" | |
| and parse_place_opt = function | |
| | {it = Parens items'; at} :: items -> | |
| let dir, items'' = parse_direction at items' in | |
| let sec, items''' = parse_section at items'' in | |
| parse_end items'''; | |
| dir sec, items | |
| | items -> | |
| After last, items | |
| and parse_direction at = function | |
| | {it = Atom "before"; _} :: items -> (fun sec -> Before sec), items | |
| | {it = Atom "after"; _} :: items -> (fun sec -> After sec), items | |
| | _ -> | |
| parse_error at "@custom annotation: malformed placement" | |
| and parse_section at = function | |
| | {it = Atom "type"; _} :: items -> Type, items | |
| | {it = Atom "import"; _} :: items -> Import, items | |
| | {it = Atom "func"; _} :: items -> Func, items | |
| | {it = Atom "table"; _} :: items -> Table, items | |
| | {it = Atom "memory"; _} :: items -> Memory, items | |
| | {it = Atom "tag"; _} :: items -> Tag, items | |
| | {it = Atom "global"; _} :: items -> Global, items | |
| | {it = Atom "export"; _} :: items -> Export, items | |
| | {it = Atom "start"; _} :: items -> Start, items | |
| | {it = Atom "elem"; _} :: items -> Elem, items | |
| | {it = Atom "code"; _} :: items -> Code, items | |
| | {it = Atom "data"; _} :: items -> Data, items | |
| | {it = Atom "datacount"; _} :: items -> DataCount, items | |
| | {it = Atom "first"; _} :: items -> first, items | |
| | {it = Atom "last"; _} :: items -> last, items | |
| | _ -> | |
| parse_error at "@custom annotation: malformed section kind" | |
| and parse_content = function | |
| | {it = String bs; _} :: items -> | |
| let bs', items' = parse_content items in | |
| bs ^ bs', items' | |
| | items -> "", items | |
| and parse_end = function | |
| | [] -> () | |
| | item :: _ -> | |
| parse_error item.at "@custom annotation: unexpected token" | |
| (* Printing *) | |
| open Sexpr | |
| let rec arrange _m mnode custom = | |
| let {name; content; place} = custom.it in | |
| let node = Node ("@custom " ^ Arrange.name name, | |
| arrange_place place :: Arrange.break_bytes content | |
| ) in | |
| match mnode with | |
| | Sexpr.Atom _ -> assert false | |
| | Node (name, secs) -> Node (name, secs @ [node]) | |
| and arrange_place = function | |
| | Before sec -> Node ("before", [Atom (arrange_sec sec)]) | |
| | After sec -> Node ("after", [Atom (arrange_sec sec)]) | |
| and arrange_sec = function | |
| | Custom -> assert false | |
| | Type -> "type" | |
| | Import -> "import" | |
| | Func -> "func" | |
| | Table -> "table" | |
| | Memory -> "memory" | |
| | Tag -> "tag" | |
| | Global -> "global" | |
| | Export -> "export" | |
| | Start -> "start" | |
| | Elem -> "elem" | |
| | Code -> "code" | |
| | Data -> "data" | |
| | DataCount -> "datacount" | |
| (* Checking *) | |
| let check m custom = | |
| let {place; _} = custom.it in | |
| assert (compare_place place (After Custom) > 0); | |
| match decode_content m custom with | |
| | None -> () | |
| | Some (module S : Custom.Section) -> | |
| S.Handler.check m S.it |