blob: 908957890aa07bb1584e9792363371f0f4b931d0 [file] [log] [blame] [edit]
open Util
open Source
open Ast
let error at msg = Error.error at "syntax" msg
let filter_nl xs = List.filter_map (function Nl -> None | Elem x -> Some x) xs
let empty_nl_list xs = filter_nl xs = []
let hd_nl_list xs = List.hd (filter_nl xs)
let last_nl_list xs = Lib.List.last (filter_nl xs)
let forall_nl_list f xs = List.for_all f (filter_nl xs)
let exists_nl_list f xs = List.exists f (filter_nl xs)
let find_nl_list f xs = List.find_opt f (filter_nl xs)
let iter_nl_list f xs = List.iter f (filter_nl xs)
let fold_nl_list f y xs = List.fold_left f y (filter_nl xs)
let map_filter_nl_list f xs = List.map f (filter_nl xs)
let map_nl_list f xs = List.map (function Nl -> Nl | Elem x -> Elem (f x)) xs
let filter_nl_list f xs = List.filter (function Nl -> true | Elem x -> f x) xs
let concat_map_nl_list f xs = List.concat_map (function Nl -> [Nl] | Elem x -> f x) xs
let concat_map_filter_nl_list f xs = List.concat_map (function Nl -> [] | Elem x -> f x) xs
let rec is_sub s i = i = String.length s || s.[i] = '_' && is_sub s (i + 1)
let strip_var_suffix id =
match String.index_opt id.it '_', String.index_opt id.it '\'' with
| None, None -> id
| Some n, None when is_sub id.it n -> id (* keep trailing underscores *)
| None, Some n | Some n, None -> String.sub id.it 0 n $ id.at
| Some n1, Some n2 -> String.sub id.it 0 (min n1 n2) $ id.at
let strip_var_sub id =
let n = ref 0 in
while !n < String.length id.it && id.it.[String.length id.it - !n - 1] = '_' do incr n done;
String.sub id.it 0 (String.length id.it - !n) $ id.at
let arg_of_exp e =
ref (ExpA e) $ e.at
let typ_of_varid id =
(match id.it with
| "bool" -> BoolT
| "nat" -> NumT `NatT
| "int" -> NumT `IntT
| "rat" -> NumT `RatT
| "real" -> NumT `RealT
| "text" -> TextT
| _ -> VarT (id, [])
) $ id.at
let rec varid_of_typ t =
(match t.it with
| VarT (id, _) -> id.it
| BoolT -> "bool"
| NumT `NatT -> "nat"
| NumT `IntT -> "int"
| NumT `RatT -> "rat"
| NumT `RealT -> "real"
| TextT -> "text"
| ParenT t1 -> (varid_of_typ t1).it
| _ -> "_"
) $ t.at
let rec typ_of_exp e =
(match e.it with
| VarE (id, []) -> (typ_of_varid id).it
| VarE (id, args) -> VarT (id, args)
| ParenE e1 -> ParenT (typ_of_exp e1)
| TupE es -> TupT (List.map typ_of_exp es)
| IterE (e1, iter) -> IterT (typ_of_exp e1, iter)
| StrE efs -> StrT (NoDots, [], map_nl_list typfield_of_expfield efs, NoDots)
| AtomE atom -> AtomT atom
| SeqE [{it = VarE (id, []); at = at1; _}; {it = ParenE e1; at = at2; _}]
when at1.right = at2.left -> (* HACK! *)
VarT (id, [ref (ExpA e1) $ e1.at])
| SeqE [{it = VarE (id, []); at = at1; _}; {it = TupE es; at = at2; _}]
when at1.right = at2.left -> (* HACK! *)
VarT (id, List.map (fun ei -> ref (ExpA ei) $ ei.at) es)
| SeqE [{it = AtomE {it = Xl.Atom.Atom id; at; _}; at = at1; _}; {it = ParenE e1; at = at2; _}]
when at1.right = at2.left -> (* HACK! *)
VarT (id $ at, [ref (ExpA e1) $ e1.at])
| SeqE [{it = AtomE {it = Xl.Atom.Atom id; at; _}; at = at1; _}; {it = TupE es; at = at2; _}]
when at1.right = at2.left -> (* HACK! *)
VarT (id $ at, List.map (fun ei -> ref (ExpA ei) $ ei.at) es)
| SeqE es -> SeqT (List.map typ_of_exp es)
| InfixE (e1, atom, e2) -> InfixT (typ_of_exp e1, atom, typ_of_exp e2)
| BrackE (l, e1, r) -> BrackT (l, typ_of_exp e1, r)
| _ -> error e.at "malformed type"
) $ e.at
and typfield_of_expfield (atom, e) =
(atom, (typ_of_exp e, []), [])
let rec exp_of_typ t =
(match t.it with
| VarT (id, args) -> VarE (id, args)
| BoolT | NumT _ | TextT -> VarE (varid_of_typ t, [])
| ParenT t1 -> ParenE (exp_of_typ t1)
| TupT ts -> TupE (List.map exp_of_typ ts)
| IterT (t1, iter) -> IterE (exp_of_typ t1, iter)
| StrT (NoDots, [], tfs, NoDots) -> StrE (map_nl_list expfield_of_typfield tfs)
| AtomT atom -> AtomE atom
| SeqT ts -> SeqE (List.map exp_of_typ ts)
| InfixT (t1, atom, t2) -> InfixE (exp_of_typ t1, atom, exp_of_typ t2)
| BrackT (l, t1, r) -> BrackE (l, exp_of_typ t1, r)
| StrT _ | CaseT _ | ConT _ | RangeT _ -> error t.at "malformed expression"
) $ t.at
and expfield_of_typfield (atom, (t, _prems), _) =
(atom, exp_of_typ t)
let expify t = function
| Some e -> e
| None -> VarE ("_" $ t.at, []) $ t.at
module Set = Set.Make(String)
let rec pat_of_typ' s t : exp option =
let (let*) = Option.bind in
match t.it with
| VarT (id, _args) ->
if Set.mem id.it !s then None else
(
(* Suppress duplicates. *)
s := Set.add id.it !s;
Some (VarE (id, []) $ t.at)
)
| BoolT | NumT _ | TextT ->
let id = varid_of_typ t in
if Set.mem id.it !s then None else
(
(* Suppress duplicates. *)
s := Set.add id.it !s;
Some (VarE (id, []) $ t.at)
)
| ParenT t1 ->
let* e1 = pat_of_typ' s t1 in
Some (ParenE e1 $ t.at)
| TupT ts ->
let* es = pats_of_typs' s ts in
Some (TupE es $ t.at)
| SeqT ts ->
let* es = pats_of_typs' s ts in
Some (SeqE es $ t.at)
| IterT (t1, iter) ->
let* e1 = pat_of_typ' s t1 in
Some (IterE (e1, iter) $ t.at)
| _ -> None
and pats_of_typs' s ts : exp list option =
let eos = List.map (pat_of_typ' s) ts in
if List.for_all ((=) None) eos then None else
Some (List.map2 expify ts eos)
let pat_of_typ t = expify t (pat_of_typ' (ref Set.empty) t)
let pats_of_typs ts = List.map2 expify ts (List.map (pat_of_typ' (ref Set.empty)) ts)
let rec sym_of_exp e =
(match e.it with
| VarE (id, args) -> VarG (id, args)
| AtomE {it = Atom id; _} -> VarG (id $ e.at, []) (* for uppercase grammar ids in show hints *)
| NumE (op, `Nat n) -> NumG (op, n)
| TextE s -> TextG s
| EpsE -> EpsG
| SeqE [{it = VarE (id, []); at = at1; _}; {it = ParenE e1; at = at2; _}]
when at1.right = at2.left -> (* HACK! *)
VarG (id, [ref (ExpA e1) $ e1.at])
| SeqE [{it = VarE (id, []); at = at1; _}; {it = TupE es; at = at2; _}]
when at1.right = at2.left -> (* HACK! *)
VarG (id, List.map (fun ei -> ref (ExpA ei) $ ei.at) es)
| SeqE [{it = AtomE {it = Xl.Atom.Atom id; at; _}; at = at1; _}; {it = ParenE e1; at = at2; _}]
when at1.right = at2.left -> (* HACK! *)
VarG (id $ at, [ref (ExpA e1) $ e1.at])
| SeqE [{it = AtomE {it = Xl.Atom.Atom id; at; _}; at = at1; _}; {it = TupE es; at = at2; _}]
when at1.right = at2.left -> (* HACK! *)
VarG (id $ at, List.map (fun ei -> ref (ExpA ei) $ ei.at) es)
| SeqE es -> SeqG (List.map (fun e -> Elem (sym_of_exp e)) es)
| ParenE e1 -> ParenG (sym_of_exp e1)
| TupE es -> TupG (List.map sym_of_exp es)
| IterE (e1, iter) -> IterG (sym_of_exp e1, iter)
| TypE (e1, t) -> AttrG (e1, sym_of_exp (exp_of_typ t))
| FuseE (e1, e2) -> FuseG (sym_of_exp e1, sym_of_exp e2)
| UnparenE e1 -> UnparenG (sym_of_exp e1)
| ArithE e -> ArithG e
| _ -> ArithG e
) $ e.at
let rec exp_of_sym g =
(match g.it with
| VarG (id, args) -> VarE (id, args)
| NumG (op, n) -> NumE (op, `Nat n)
| TextG t -> TextE t
| EpsG -> EpsE
| SeqG gs -> SeqE (map_filter_nl_list exp_of_sym gs)
| ParenG g1 -> ParenE (exp_of_sym g1)
| TupG gs -> TupE (List.map exp_of_sym gs)
| IterG (g1, iter) -> IterE (exp_of_sym g1, iter)
| ArithG e -> ArithE e
| AttrG (e, g2) -> TypE (e, typ_of_exp (exp_of_sym g2))
| FuseG (g1, g2) -> FuseE (exp_of_sym g1, exp_of_sym g2)
| UnparenG g1 -> UnparenE (exp_of_sym g1)
| _ -> error g.at "malformed expression"
) $ g.at
let exp_of_arg a =
match !(a.it) with
| ExpA e -> e
| _ -> error a.at "malformed expression"
let rec param_of_arg a =
(match !(a.it) with
| ExpA e ->
(match e.it with
| TypE ({it = VarE (id, []); _}, t) -> ExpP (id, t)
| VarE (id, args) ->
ExpP (id, typ_of_exp (VarE (strip_var_suffix id, args) $ e.at))
| TypE ({it = CallE (id, as_); _}, t) ->
DefP (id, List.map param_of_arg as_, t)
| _ -> ExpP ("_" $ e.at, typ_of_exp e)
)
| TypA {it = VarT (id, []); _} ->
if id.it <> (strip_var_suffix id).it then
error id.at "invalid identifer suffix in binding position";
TypP id
| GramA {it = AttrG ({it = VarE (id, []); _}, g); _} ->
GramP (id, [], typ_of_exp (exp_of_sym g))
| _ -> error a.at "malformed parameter"
) $ a.at
let arg_of_param p =
(match p.it with
| ExpP (id, _t) -> ExpA ((*TypE ( *)VarE (id, []) $ id.at(*, t) $ p.at*))
| TypP id -> TypA (VarT (id, []) $ id.at)
| GramP (id, _ps, _t) -> GramA (VarG (id, []) $ id.at)
| DefP (id, _ps, _t) -> DefA id
) |> ref $ p.at