blob: 9fc74e5b68f6feee3b243f1631092cb22850c1b3 [file] [log] [blame] [edit]
(* 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