let min_precedence = 0
let max_precedence = 100
-let default_precedence = 50
-
-let let_in_prec = 10
-let binder_prec = 20
-let apply_prec = 70
-let simple_prec = 90
-
-let let_in_assoc = Gramext.NonA
-let binder_assoc = Gramext.RightA
-let apply_assoc = Gramext.LeftA
-let simple_assoc = Gramext.NonA
let level1_pattern =
Grammar.Entry.create level1_pattern_grammar "level1_pattern"
let level2_ast = Grammar.Entry.create level2_ast_grammar "level2_ast"
let term = Grammar.Entry.create level2_ast_grammar "term"
+let let_defs = Grammar.Entry.create level2_ast_grammar "let_defs"
let level2_meta = Grammar.Entry.create level2_meta_grammar "level2_meta"
-let level3_term = Grammar.Entry.create level2_ast_grammar "level3_term"
-let notation = (* level1 <-> level 2 *)
- Grammar.Entry.create level2_ast_grammar "notation"
-let interpretation = (* level2 <-> level 3 *)
- Grammar.Entry.create level2_ast_grammar "interpretation"
-let phrase = Grammar.Entry.create level2_ast_grammar "phrase"
-
let return_term loc term = ()
-let fail floc msg =
- let (x, y) = loc_of_floc floc in
- failwith (sprintf "Error at characters %d - %d: %s" x y msg)
-
let int_of_string s =
try
Pervasives.int_of_string s
(** {2 Grammar extension} *)
-let symbol s = Gramext.Stoken ("SYMBOL", s)
-let ident s = Gramext.Stoken ("IDENT", s)
-let number s = Gramext.Stoken ("NUMBER", s)
+let gram_symbol s = Gramext.Stoken ("SYMBOL", s)
+let gram_ident s = Gramext.Stoken ("IDENT", s)
+let gram_number s = Gramext.Stoken ("NUMBER", s)
+let gram_keyword s = Gramext.Stoken ("", s)
+let gram_term = Gramext.Sself
-let g_symbol_of_literal =
+let gram_of_literal =
function
- | `Symbol s -> symbol s
- | `Keyword s -> ident s
- | `Number s -> number s
+ | `Symbol s -> gram_symbol s
+ | `Keyword s -> gram_keyword s
+ | `Number s -> gram_number s
type binding =
| NoBinding
assert false
and aux_literal =
function
- | `Symbol s -> [NoBinding, symbol s]
- | `Keyword s -> [NoBinding, ident s]
- | `Number s -> [NoBinding, number s]
+ | `Symbol s -> [NoBinding, gram_symbol s]
+ | `Keyword s ->
+ (* assumption: s will be registered as a keyword with the lexer *)
+ [NoBinding, gram_keyword s]
+ | `Number s -> [NoBinding, gram_number s]
and aux_layout = function
- | Sub (p1, p2) -> aux p1 @ [NoBinding, symbol "\\sub"] @ aux p2
- | Sup (p1, p2) -> aux p1 @ [NoBinding, symbol "\\sup"] @ aux p2
- | Below (p1, p2) -> aux p1 @ [NoBinding, symbol "\\below"] @ aux p2
- | Above (p1, p2) -> aux p1 @ [NoBinding, symbol "\\above"] @ aux p2
- | Frac (p1, p2) -> aux p1 @ [NoBinding, symbol "\\frac"] @ aux p2
- | Atop (p1, p2) -> aux p1 @ [NoBinding, symbol "\\atop"] @ aux p2
- | Over (p1, p2) -> aux p1 @ [NoBinding, symbol "\\over"] @ aux p2
+ | Sub (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\sub"] @ aux p2
+ | Sup (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\sup"] @ aux p2
+ | Below (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\below"] @ aux p2
+ | Above (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\above"] @ aux p2
+ | Frac (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\frac"] @ aux p2
+ | Atop (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\atop"] @ aux p2
+ | Over (p1, p2) -> aux p1 @ [NoBinding, gram_symbol "\\over"] @ aux p2
| Root (p1, p2) ->
- [NoBinding, symbol "\\root"] @ aux p2 @ [NoBinding, symbol "\\of"]
- @ aux p1
- | Sqrt p -> [NoBinding, symbol "\\sqrt"] @ aux p
+ [NoBinding, gram_symbol "\\root"] @ aux p2
+ @ [NoBinding, gram_symbol "\\of"] @ aux p1
+ | Sqrt p -> [NoBinding, gram_symbol "\\sqrt"] @ aux p
| Break -> []
| Box (_, pl) -> List.flatten (List.map aux pl)
+ | Group pl -> List.flatten (List.map aux pl)
and aux_magic magic =
match magic with
| Opt p ->
let action (env_list : CicNotationEnv.t list) (loc : location) =
CicNotationEnv.coalesce_env p_names env_list
in
- let g_symbol s =
+ let gram_of_list s =
match magic with
| List0 (_, None) -> Gramext.Slist0 s
| List1 (_, None) -> Gramext.Slist1 s
- | List0 (_, Some l) -> Gramext.Slist0sep (s, g_symbol_of_literal l)
- | List1 (_, Some l) -> Gramext.Slist1sep (s, g_symbol_of_literal l)
+ | List0 (_, Some l) -> Gramext.Slist0sep (s, gram_of_literal l)
+ | List1 (_, Some l) -> Gramext.Slist1sep (s, gram_of_literal l)
| _ -> assert false
in
[ Env (List.map list_declaration p_names),
Gramext.srules
- [ [ g_symbol (Gramext.srules [ p_atoms, p_action ]) ],
+ [ [ gram_of_list (Gramext.srules [ p_atoms, p_action ]) ],
Gramext.action action ] ]
| _ -> assert false
and aux_variable =
function
- | NumVar s -> [Binding (s, NumType), number ""]
- | TermVar s -> [Binding (s, TermType), Gramext.Sself]
- | IdentVar s -> [Binding (s, StringType), ident ""]
+ | NumVar s -> [Binding (s, NumType), gram_number ""]
+ | TermVar s -> [Binding (s, TermType), gram_term]
+ | IdentVar s -> [Binding (s, StringType), gram_ident ""]
| Ascription (p, s) -> assert false (* TODO *)
| FreshVar _ -> assert false
and inner_pattern p =
in
aux pattern
-let level_of_int precedence =
+let level_of precedence associativity =
if precedence < min_precedence || precedence > max_precedence then
raise (Level_not_found precedence);
- string_of_int precedence
+ let assoc_string =
+ match associativity with
+ | Gramext.NonA -> "N"
+ | Gramext.LeftA -> "L"
+ | Gramext.RightA -> "R"
+ in
+ string_of_int precedence ^ assoc_string
type rule_id = Token.t Gramext.g_symbol list
-let extend level1_pattern ?(precedence = default_precedence)
- ?associativity action
-=
+ (* mapping: rule_id -> owned keywords. (rule_id, string list) Hashtbl.t *)
+let owned_keywords = Hashtbl.create 23
+
+let extend level1_pattern ~precedence ~associativity action =
let p_bindings, p_atoms =
List.split (extract_term_production level1_pattern)
in
- let level = level_of_int precedence in
+ let level = level_of precedence associativity in
let p_names = flatten_opt p_bindings in
let _ =
Grammar.extend
[ Grammar.Entry.obj (term: 'a Grammar.Entry.e),
Some (Gramext.Level level),
[ None,
- associativity,
+ Some associativity,
[ p_atoms,
(make_action
(fun (env: CicNotationEnv.t) (loc: location) -> (action env loc))
p_bindings) ]]]
in
- p_atoms
-
-let delete atoms = Grammar.delete_rule term atoms
+ let keywords = CicNotationUtil.keywords_of_term level1_pattern in
+ let rule_id = p_atoms in
+ List.iter CicNotationLexer.add_level2_ast_keyword keywords;
+ Hashtbl.add owned_keywords rule_id keywords; (* keywords may be [] *)
+ rule_id
+
+let delete rule_id =
+ let atoms = rule_id in
+ (try
+ let keywords = Hashtbl.find owned_keywords rule_id in
+ List.iter CicNotationLexer.remove_level2_ast_keyword keywords
+ with Not_found -> assert false);
+ Grammar.delete_rule term atoms
(** {2 Grammar} *)
let parse_level2_ast_ref = ref (fun _ -> assert false)
let parse_level2_meta_ref = ref (fun _ -> assert false)
+let fold_cluster binder terms ty body =
+ List.fold_right
+ (fun term body -> Binder (binder, (term, ty), body))
+ terms body (* terms are names: either Ident or FreshVar *)
+
let fold_binder binder pt_names body =
- let fold_cluster binder terms ty body =
- List.fold_right
- (fun term body -> Binder (binder, (term, ty), body))
- terms body (* terms are names: either Ident or FreshVar *)
- in
List.fold_right
(fun (names, ty) body -> fold_cluster binder names ty body)
pt_names body
let mk_level_list first last =
let rec aux acc = function
| i when i < first -> acc
- | i -> aux ((Some (string_of_int i), None, []) :: acc) (i - 1)
+ | i ->
+ aux
+ ((Some (string_of_int i ^ "N"), Some Gramext.NonA, [])
+ :: (Some (string_of_int i ^ "L"), Some Gramext.LeftA, [])
+ :: (Some (string_of_int i ^ "R"), Some Gramext.RightA, [])
+ :: acc)
+ (i - 1)
in
aux [] last
in
| SYMBOL "\\root"; index = SELF; SYMBOL "\\OF"; arg = SELF ->
return_term loc (Layout (Root (arg, index)))
| "hbox"; LPAREN; p = l1_pattern; RPAREN ->
- return_term loc (CicNotationUtil.boxify p)
+ return_term loc (Layout (Box ((H, false, false), p)))
| "vbox"; LPAREN; p = l1_pattern; RPAREN ->
- return_term loc (CicNotationUtil.boxify p)
+ return_term loc (Layout (Box ((V, false, false), p)))
| "hvbox"; LPAREN; p = l1_pattern; RPAREN ->
- return_term loc (CicNotationUtil.boxify p)
+ return_term loc (Layout (Box ((HV, false, false), p)))
| "hovbox"; LPAREN; p = l1_pattern; RPAREN ->
- return_term loc (CicNotationUtil.boxify p)
+ return_term loc (Layout (Box ((HOV, false, false), p)))
| "break" -> return_term loc (Layout Break)
(* | SYMBOL "\\SPACE" -> return_term loc (Layout Space) *)
- | "LPAREN"; p = l1_pattern; "RPAREN" ->
- return_term loc (CicNotationUtil.boxify p)
+ | LPAREN; p = l1_pattern; RPAREN ->
+ return_term loc (CicNotationUtil.group p)
]
| "simple" NONA
[ i = IDENT -> return_term loc (Variable (TermVar i))
END
(* }}} *)
-
+(* {{{ Grammar for ast magics, notation level 2 *)
EXTEND
GLOBAL: level2_meta;
l2_variable: [
]
];
END
+(* }}} *)
-EXTEND
- GLOBAL: level2_ast term
- level3_term
- notation interpretation
- phrase;
(* {{{ Grammar for ast patterns, notation level 2 *)
+EXTEND
+ GLOBAL: level2_ast term let_defs;
level2_ast: [ [ p = term -> p ] ];
sort: [
- [ IDENT "Prop" -> `Prop
- | IDENT "Set" -> `Set
- | IDENT "Type" -> `Type
+ [ "Prop" -> `Prop
+ | "Set" -> `Set
+ | "Type" -> `Type
+ | "CProp" -> `CProp
]
];
explicit_subst: [
[ SYMBOL "["; substs = LIST0 meta_subst; SYMBOL "]" -> substs ]
];
possibly_typed_name: [
- [ LPAREN; id = bound_name; SYMBOL ":"; typ = term; RPAREN ->
+ [ LPAREN; id = single_arg; SYMBOL ":"; typ = term; RPAREN ->
id, Some typ
- | id = bound_name -> id, None
+ | arg = single_arg -> arg, None
]
];
match_pattern: [
| SYMBOL <:unicode<lambda>> (* λ *) -> `Lambda
]
];
- bound_name: [
- [ i = IDENT -> Ident (i, None)
- | SYMBOL "\\FRESH"; i = IDENT -> Variable (FreshVar i)
- ]
+ arg: [
+ [ LPAREN; names = LIST1 IDENT SEP SYMBOL ",";
+ SYMBOL ":"; ty = term; RPAREN ->
+ List.map (fun n -> Ident (n, None)) names, Some ty
+ | name = IDENT -> [Ident (name, None)], None
+ | blob = UNPARSED_META ->
+ let meta = !parse_level2_meta_ref (Stream.of_string blob) in
+ match meta with
+ | Variable (FreshVar _) -> [meta], None
+ | Variable (TermVar "_") -> [Ident ("_", None)], None
+ | _ -> failwith "Invalid bound name."
+ ]
];
- bound_names: [
- [ vars = LIST1 bound_name SEP SYMBOL ",";
- ty = OPT [ SYMBOL ":"; p = term -> p ] ->
- [ vars, ty ]
- | clusters = LIST1 [
- LPAREN;
- vars = LIST1 bound_name SEP SYMBOL ",";
- ty = OPT [ SYMBOL ":"; p = term -> p ];
- RPAREN ->
- vars, ty
- ] ->
- clusters
+ single_arg: [
+ [ name = IDENT -> Ident (name, None)
+ | blob = UNPARSED_META ->
+ let meta = !parse_level2_meta_ref (Stream.of_string blob) in
+ match meta with
+ | Variable (FreshVar _) -> meta
+ | Variable (TermVar "_") -> Ident ("_", None)
+ | _ -> failwith "Invalid index name."
]
];
induction_kind: [
- [ IDENT "rec" -> `Inductive
- | IDENT "corec" -> `CoInductive
+ [ "rec" -> `Inductive
+ | "corec" -> `CoInductive
]
];
let_defs: [
[ defs = LIST1 [
- name = bound_name; args = bound_names;
- index_name = OPT [ IDENT "on"; id = bound_name -> id ];
+ name = single_arg;
+ args = LIST1 arg;
+ index_name = OPT [ "on"; id = single_arg -> id ];
ty = OPT [ SYMBOL ":" ; p = term -> p ];
SYMBOL <:unicode<def>> (* ≝ *); body = term ->
let body = fold_binder `Lambda args body in
let index =
match index_name with
| None -> 0
- | Some name -> find_arg name 0 args
+ | Some index_name -> find_arg index_name 0 args
in
(name, ty), body, index
- ] SEP IDENT "and" ->
+ ] SEP "and" ->
defs
]
];
- term: LEVEL "10" (* let in *)
- [ "10" NONA
- [ IDENT "let"; var = possibly_typed_name; SYMBOL <:unicode<def>> (* ≝ *);
- p1 = term; "in"; p2 = term ->
- return_term loc (LetIn (var, p1, p2))
- | IDENT "let"; k = induction_kind; defs = let_defs; IDENT "in";
- body = term ->
- return_term loc (LetRec (k, defs, body))
- ]
- ];
- term: LEVEL "20" (* binder *)
- [ "20" RIGHTA
- [ b = binder; names = bound_names; SYMBOL "."; body = term ->
- return_term loc (fold_binder b names body)
+ binder_vars: [
+ [ vars = [
+ l = LIST1 single_arg SEP SYMBOL "," -> l
+ | SYMBOL "_" -> [Ident ("_", None)] ];
+ typ = OPT [ SYMBOL ":"; t = term -> t ] -> (vars, typ)
+ | LPAREN;
+ vars = [
+ l = LIST1 single_arg SEP SYMBOL "," -> l
+ | SYMBOL "_" -> [Ident ("_", None)] ];
+ typ = OPT [ SYMBOL ":"; t = term -> t ];
+ RPAREN -> (vars, typ)
+ ]
+ ];
+ term: LEVEL "10N" [ (* let in *)
+ [ "let"; var = possibly_typed_name; SYMBOL <:unicode<def>> (* ≝ *);
+ p1 = term; "in"; p2 = term ->
+ return_term loc (LetIn (var, p1, p2))
+ | "let"; k = induction_kind; defs = let_defs; "in";
+ body = term ->
+ return_term loc (LetRec (k, defs, body))
+ ]
+ ];
+ term: LEVEL "20R" (* binder *)
+ [
+ [ b = binder; (vars, typ) = binder_vars; SYMBOL "."; body = term ->
+ return_term loc (fold_cluster b vars typ body)
]
];
- term: LEVEL "70" (* apply *)
- [ "70" LEFTA
+ term: LEVEL "70L" (* apply *)
+ [
[ p1 = term; p2 = term ->
let rec aux = function
| Appl (hd :: tl)
return_term loc (Appl (aux p1 @ [p2]))
]
];
- term: LEVEL "90" (* simple *)
- [ "90" NONA
+ term: LEVEL "90N" (* simple *)
+ [
[ id = IDENT -> return_term loc (Ident (id, None))
| id = IDENT; s = explicit_subst -> return_term loc (Ident (id, Some s))
| s = CSYMBOL -> return_term loc (Symbol (s, 0))
| u = URI -> return_term loc (Uri (u, None))
| n = NUMBER -> return_term loc (Num (n, 0))
| IMPLICIT -> return_term loc (Implicit)
+ | PLACEHOLDER -> return_term loc UserInput
| m = META -> return_term loc (Meta (int_of_string m, []))
| m = META; s = meta_substs -> return_term loc (Meta (int_of_string m, s))
| s = sort -> return_term loc (Sort s)
| outtyp = OPT [ SYMBOL "["; ty = term; SYMBOL "]" -> ty ];
- IDENT "match"; t = term;
- indty_ident = OPT [ SYMBOL ":"; id = IDENT -> id ];
- IDENT "with"; SYMBOL "[";
+ "match"; t = term;
+ indty_ident = OPT [ "in"; id = IDENT -> id ];
+ "with"; SYMBOL "[";
patterns = LIST0 [
lhs = match_pattern; SYMBOL <:unicode<Rightarrow>> (* ⇒ *);
rhs = term ->
SYMBOL "]" ->
return_term loc (Case (t, indty_ident, outtyp, patterns))
| LPAREN; p1 = term; SYMBOL ":"; p2 = term; RPAREN ->
- return_term loc (Appl [ Symbol ("cast", 0); p1; p2 ])
+ return_term loc (Cast (p1, p2))
| LPAREN; p = term; RPAREN -> p
| blob = UNPARSED_META -> !parse_level2_meta_ref (Stream.of_string blob)
]
];
-(* }}} *)
-(* {{{ Grammar for interpretation, notation level 3 *)
- argument: [
- [ id = IDENT -> IdentArg (0, id)
- | l = LIST1 [ SYMBOL <:unicode<eta>> (* η *) -> () ] SEP SYMBOL ".";
- SYMBOL "."; id = IDENT ->
- IdentArg (List.length l, id)
- ]
- ];
- level3_term: [
- [ u = URI -> UriPattern (UriManager.uri_of_string u)
- | id = IDENT -> VarPattern id
- | LPAREN; terms = LIST1 SELF; RPAREN ->
- (match terms with
- | [] -> assert false
- | [term] -> term
- | terms -> ApplPattern terms)
- ]
- ];
-(* }}} *)
-(* {{{ Notation glues *)
- associativity: [
- [ IDENT "left"; IDENT "associative" -> Gramext.LeftA
- | IDENT "right"; IDENT "associative" -> Gramext.RightA
- | IDENT "non"; IDENT "associative" -> Gramext.NonA
- ]
- ];
- precedence: [
- [ IDENT "with"; IDENT "precedence"; n = NUMBER -> int_of_string n ]
- ];
- notation: [
- [ s = QSTRING;
- assoc = OPT associativity; prec = OPT precedence;
- IDENT "for";
- p2 =
- [ blob = UNPARSED_AST -> !parse_level2_ast_ref (Stream.of_string blob)
- | blob = UNPARSED_META ->
- !parse_level2_meta_ref (Stream.of_string blob) ]
- ->
- (!parse_level1_pattern_ref (Stream.of_string s), assoc, prec, p2)
- ]
- ];
- interpretation: [
- [ s = CSYMBOL; args = LIST1 argument; SYMBOL "="; t = level3_term ->
- (s, args, t)
- ]
- ];
-(* }}} *)
-(* {{{ Top-level phrases *)
- phrase: [
- [ IDENT "print"; t = term; SYMBOL "." -> Print t
- | IDENT "notation"; (l1, assoc, prec, l2) = notation; SYMBOL "." ->
- Notation (l1, assoc, prec, l2)
- | IDENT "interpretation"; (symbol, args, l3) = interpretation; SYMBOL "." ->
- Interpretation ((symbol, args), l3)
- | IDENT "render"; u = URI; SYMBOL "." -> Render (UriManager.uri_of_string u)
- ]
- ];
-(* }}} *)
END
+(* }}} *)
(** {2 API implementation} *)
exc_located_wrapper (fun () -> Grammar.Entry.parse level2_ast stream)
let parse_level2_meta stream =
exc_located_wrapper (fun () -> Grammar.Entry.parse level2_meta stream)
-let parse_interpretation stream =
- exc_located_wrapper (fun () -> Grammar.Entry.parse level3_term stream)
-let parse_phrase stream =
- exc_located_wrapper (fun () -> Grammar.Entry.parse phrase stream)
let _ =
parse_level1_pattern_ref := parse_level1_pattern;