diff --git a/examples/einstein.why b/examples/einstein.why index 4fe343934de8f9f73b71d8f16891107228b21f41..562cb7499eb7be920c1535b097a451318348702b 100644 --- a/examples/einstein.why +++ b/examples/einstein.why @@ -9,10 +9,10 @@ theory Bijection type u logic of t : u - logic to u : t + logic to_ u : t - axiom To_of : forall x : t. to (of x) = x - axiom Of_to : forall y : u. of (to y) = y + axiom To_of : forall x : t. to_ (of x) = x + axiom Of_to : forall y : u. of (to_ y) = y end theory Einstein "Einstein's problem" @@ -52,7 +52,7 @@ theory EinsteinHints "Hints" use import Einstein (* The Englishman lives in a red house *) - axiom Hint1: Color.of (Owner.to Englishman) = Red + axiom Hint1: Color.of (Owner.to_ Englishman) = Red (* The Swede has dogs *) axiom Hint2: Pet.of Swede = Dogs @@ -61,16 +61,16 @@ theory EinsteinHints "Hints" axiom Hint3: Drink.of Dane = Tea (* The green house is on the left of the white one *) - axiom Hint4: leftof (Color.to Green) (Color.to White) + axiom Hint4: leftof (Color.to_ Green) (Color.to_ White) (* The green house's owner drinks coffee *) - axiom Hint5: Drink.of (Owner.of (Color.to Green)) = Coffee + axiom Hint5: Drink.of (Owner.of (Color.to_ Green)) = Coffee (* The person who smokes Pall Mall has birds *) - axiom Hint6: Pet.of (Cigar.to PallMall) = Birds + axiom Hint6: Pet.of (Cigar.to_ PallMall) = Birds (* The yellow house's owner smokes Dunhill *) - axiom Hint7: Cigar.of (Owner.of (Color.to Yellow)) = Dunhill + axiom Hint7: Cigar.of (Owner.of (Color.to_ Yellow)) = Dunhill (* In the house in the center lives someone who drinks milk *) axiom Hint8: Drink.of (Owner.of H3) = Milk @@ -80,15 +80,15 @@ theory EinsteinHints "Hints" (* The man who smokes Blends lives next to the one who has cats *) axiom Hint10: neighbour - (Owner.to (Cigar.to Blend)) (Owner.to (Pet.to Cats)) + (Owner.to_ (Cigar.to_ Blend)) (Owner.to_ (Pet.to_ Cats)) (* The man who owns a horse lives next to the one who smokes Dunhills *) axiom Hint11: neighbour - (Owner.to (Pet.to Horse)) (Owner.to (Cigar.to Dunhill)) + (Owner.to_ (Pet.to_ Horse)) (Owner.to_ (Cigar.to_ Dunhill)) (* The man who smokes Blue Masters drinks beer *) axiom Hint12: - Drink.of (Cigar.to BlueMaster) = Beer + Drink.of (Cigar.to_ BlueMaster) = Beer (* The German smokes Prince *) axiom Hint13: @@ -96,11 +96,11 @@ theory EinsteinHints "Hints" (* The Norwegian lives next to the blue house *) axiom Hint14: - neighbour (Owner.to Norwegian) (Color.to Blue) + neighbour (Owner.to_ Norwegian) (Color.to_ Blue) (* The man who smokes Blends has a neighbour who drinks water *) axiom Hint15: - neighbour (Owner.to (Cigar.to Blend)) (Owner.to (Drink.to Water)) + neighbour (Owner.to_ (Cigar.to_ Blend)) (Owner.to_ (Drink.to_ Water)) end @@ -112,8 +112,8 @@ theory Goals "Goals about Einstein's problem" (* lemma Last_House_Not_Green: Color.of H5 <> Green *) (* lemma Blue_not_Red: Blue <> Red *) - (* lemma Englishman_not_H2: Owner.to Englishman <> H2 *) - (* lemma Englishman_not_H1: Owner.to Englishman <> H1 *) + (* lemma Englishman_not_H2: Owner.to_ Englishman <> H2 *) + (* lemma Englishman_not_H1: Owner.to_ Englishman <> H1 *) (* lemma Second_House_Blue: Color.of H2 = Blue *) (* lemma Green_H4 : Color.of H4 = Green *) @@ -121,7 +121,7 @@ theory Goals "Goals about Einstein's problem" (* lemma Red_H3 : Color.of H3 = Red *) (* lemma Yellow_H1 : Color.of H1 = Yellow *) - goal G: Pet.to Fish = German + goal G: Pet.to_ Fish = German end diff --git a/src/parser/lexer.mll b/src/parser/lexer.mll index 539c25585395c1e4c027cf8dc792ca3de7b8ccf9..f72c408547141412adfff785c2f21ad7cd12e2a0 100644 --- a/src/parser/lexer.mll +++ b/src/parser/lexer.mll @@ -75,6 +75,35 @@ "type", TYPE; "use", USE; "with", WITH; + (* programs *) + "absurd", ABSURD; + "any", ANY; + "assert", ASSERT; + "assume", ASSUME; + "begin", BEGIN; + "check", CHECK; + "do", DO; + "done", DONE; + "downto", DOWNTO; + "exception", EXCEPTION; + "for", FOR; + "fun", FUN; + "ghost", GHOST; + "invariant", INVARIANT; + "label", LABEL; + "model", MODEL; + "module", MODULE; + "mutable", MUTABLE; + "parameter", PARAMETER; + "raise", RAISE; + "raises", RAISES; + "reads", READS; + "rec", REC; + "to", TO; + "try", TRY; + "variant", VARIANT; + "while", WHILE; + "writes", WRITES; ] let newline lexbuf = @@ -179,8 +208,14 @@ rule token = parse { LEFTPAR } | ")" { RIGHTPAR } + | "{" + { LEFTBRC } + | "}" + { RIGHTBRC } | ":" { COLON } + | ";" + { SEMICOLON } | "->" { ARROW } | "<->" diff --git a/src/parser/parser.pre.mly b/src/parser/parser.pre.mly index 9d94e27f13b75531c95c4e94be4c8855a2338bd3..18f9d95c6bf64deaca9cc7d0f9ecbc4a77b4544e 100644 --- a/src/parser/parser.pre.mly +++ b/src/parser/parser.pre.mly @@ -90,6 +90,53 @@ | Parsing.Parse_error -> Format.fprintf fmt "syntax error" | _ -> raise exn ) + + let mk_expr d = { expr_loc = loc (); expr_desc = d } + let mk_expr_i i d = { expr_loc = loc_i i; expr_desc = d } + + let cast_body c ((p,e,q) as t) = match c with + | None -> t + | Some pt -> p, { e with expr_desc = Ecast (e, pt) }, q + + let join (b,_) (_,e) = (b,e) + + let rec mk_apply f = function + | [] -> + assert false + | [a] -> + Eapply (f, a) + | a :: l -> + let loc = join f.expr_loc a.expr_loc in + mk_apply { expr_loc = loc; expr_desc = Eapply (f, a) } l + + let mk_apply_id id = + let e = + { expr_desc = Eident (Qident id); expr_loc = id.id_loc } + in + mk_apply e + + let mk_infix e1 op e2 = + let id = { id = infix op; id_lab = []; id_loc = loc_i 2 } in + mk_expr (mk_apply_id id [e1; e2]) + + let mk_prefix op e1 = + let id = { id = prefix op; id_lab = []; id_loc = loc_i 1 } in + mk_expr (mk_apply_id id [e1]) + + let exit_exn () = Qident { id = "%Exit"; id_lab = []; id_loc = loc () } + let id_anonymous () = { id = "_"; id_lab = []; id_loc = loc () } + let id_unit () = { id = "unit"; id_lab = []; id_loc = loc () } + let ty_unit () = Tpure (PPTtyapp ([], Qident (id_unit ()))) + + let id_lt_nat () = Qident { id = "lt_nat"; id_lab = []; id_loc = loc () } + + let empty_effect = { pe_reads = []; pe_writes = []; pe_raises = [] } + + let type_c p ty ef q = + { pc_result_type = ty; + pc_effect = ef; + pc_pre = p; + pc_post = q; } %} /* Tokens */ @@ -108,6 +155,12 @@ %token LET LOGIC MATCH META NAMESPACE NOT PROP OR %token THEN THEORY TRUE TYPE USE WITH +/* program keywords */ + +%token ABSURD ANY ASSERT ASSUME BEGIN CHECK DO DONE DOWNTO EXCEPTION FOR +%token FUN GHOST INVARIANT LABEL MODEL MODULE MUTABLE PARAMETER RAISE +%token RAISES READS REC TO TRY VARIANT WHILE WRITES + /* symbols */ %token ARROW ASYM_AND ASYM_OR @@ -122,9 +175,22 @@ %token EOF +/* program symbols */ + +%token LEFTBRC RIGHTBRC SEMICOLON + /* Precedences */ -%nonassoc DOT ELSE IN +%nonassoc prec_post +%nonassoc BAR + +%nonassoc prec_triple +%nonassoc prec_simple + +%nonassoc IN +%right SEMICOLON +%nonassoc prec_no_else +%nonassoc DOT ELSE %nonassoc prec_named %nonassoc COLON @@ -137,6 +203,7 @@ %left OP3 %left OP4 %nonassoc prefix_op +%left prec_app /* Entry points */ @@ -146,6 +213,8 @@ %start list0_decl_eof %type <Theory.theory Theory.Mnm.t> logic_file_eof %start logic_file_eof +%type <Ptree.program_file> program_file +%start program_file %% logic_file_eof: @@ -476,13 +545,18 @@ list1_lexpr_arg: | lexpr_arg list1_lexpr_arg { $1::$2 } ; +constant: +| INTEGER + { Term.ConstInt $1 } +| FLOAT + { Term.ConstReal $1 } +; + lexpr_arg: | qualid { mk_pp (PPvar $1) } -| INTEGER - { mk_pp (PPconst (Term.ConstInt $1)) } -| FLOAT - { mk_pp (PPconst (Term.ConstReal $1)) } +| constant + { mk_pp (PPconst $1) } | TRUE { mk_pp PPtrue } | FALSE @@ -662,6 +736,7 @@ lident_rich: lident: | LIDENT { mk_id $1 (loc ()) } +| MODEL { mk_id "model" (loc ()) } ; lident_op: @@ -738,3 +813,415 @@ bar_: | BAR { () } ; +/****************************************************************************/ + +program_file: +| list0_module_ EOF { $1 } +; + +list0_module_: +| /* epsilon */ + { [] } +| list1_module_ + { $1 } +; + +list1_module_: +| module_ + { [$1] } +| module_ list1_module_ + { $1 :: $2 } +; + +module_: +| MODULE uident labels list0_program_decl END + { { mod_name = $2; mod_labels = $3; mod_decl = $4 } } +; + +list0_program_decl: +| /* epsilon */ + { [] } +| list1_program_decl + { $1 } +; + +list1_program_decl: +| program_decl + { [$1] } +| program_decl list1_program_decl + { $1 :: $2 } +; + +program_decl: +| decl + { Dlogic $1 } +| LET lident labels list1_type_v_binder opt_cast EQUAL triple + { Dlet (add_lab $2 $3, mk_expr_i 7 (Efun ($4, cast_body $5 $7))) } +| LET lident labels EQUAL FUN list1_type_v_binder ARROW triple + { Dlet (add_lab $2 $3, mk_expr_i 8 (Efun ($6, $8))) } +| LET REC list1_recfun_sep_and + { Dletrec $3 } +| PARAMETER lident labels COLON type_v + { Dparam (add_lab $2 $3, $5) } +| EXCEPTION uident labels + { Dexn (add_lab $2 $3, None) } +| EXCEPTION uident labels pure_type + { Dexn (add_lab $2 $3, Some $4) } +| USE use_module + { $2 } +| NAMESPACE namespace_import uident list0_program_decl END + { Dnamespace ($3, $2, $4) } +| MUTABLE TYPE lident type_args model + { Dmutable_type ($3, $4, $5) } +; + +use_module: +| imp_exp MODULE tqualid + { Duse ($3, $1, None) } +| imp_exp MODULE tqualid AS uident + { Duse ($3, $1, Some $5) } +; + +model: +| /* epsilon */ { None } +| MODEL pure_type { Some $2 } +; + +list1_recfun_sep_and: +| recfun { [ $1 ] } +| recfun WITH list1_recfun_sep_and { $1 :: $3 } +; + +recfun: +| lident labels list1_type_v_binder opt_cast opt_variant EQUAL triple + { add_lab $1 $2, $3, $5, cast_body $4 $7 } +; + +expr: +| simple_expr %prec prec_simple + { $1 } +| expr EQUAL expr + { mk_infix $1 "=" $3 } +| expr LTGT expr + { let t = mk_infix $1 "=" $3 in + mk_expr (mk_apply_id { id = "notb"; id_lab = []; id_loc = loc () } [t]) } +| expr OP1 expr + { mk_infix $1 $2 $3 } +| expr OP2 expr + { mk_infix $1 $2 $3 } +| expr OP3 expr + { mk_infix $1 $2 $3 } +| expr OP4 expr + { mk_infix $1 $2 $3 } +| NOT expr %prec prefix_op + { mk_expr (mk_apply_id { id = "notb"; id_lab = []; id_loc = loc () } [$2]) } +| any_op expr %prec prefix_op + { mk_prefix $1 $2 } +/* +| expr COLONEQUAL expr + { mk_infix $1 ":=" $3 } +*/ +| simple_expr list1_simple_expr %prec prec_app + { mk_expr (mk_apply $1 $2) } +| IF expr THEN expr ELSE expr + { mk_expr (Eif ($2, $4, $6)) } +| IF expr THEN expr %prec prec_no_else + { mk_expr (Eif ($2, $4, mk_expr Eskip)) } +| expr SEMICOLON expr + { mk_expr (Esequence ($1, $3)) } +| assertion_kind annotation + { mk_expr (Eassert ($1, $2)) } +/* +| expr AMPAMP expr + { mk_expr (Elazy (LazyAnd, $1, $3)) } +| expr BARBAR expr + { mk_expr (Elazy (LazyOr, $1, $3)) } +*/ +| LET pattern EQUAL expr IN expr + { match $2.pat_desc with + | PPpvar id -> mk_expr (Elet (id, $4, $6)) + | _ -> mk_expr (Ematch ($4, [$2, $6])) } +| LET lident labels list1_type_v_binder EQUAL triple IN expr + { mk_expr (Elet (add_lab $2 $3, mk_expr_i 6 (Efun ($4, $6)), $8)) } +| LET REC list1_recfun_sep_and IN expr + { mk_expr (Eletrec ($3, $5)) } +| FUN list1_type_v_binder ARROW triple + { mk_expr (Efun ($2, $4)) } +| MATCH expr WITH bar_ program_match_cases END + { mk_expr (Ematch ($2, $5)) } +| MATCH expr COMMA list1_expr_sep_comma WITH bar_ program_match_cases END + { mk_expr (Ematch (mk_expr (Etuple ($2::$4)), $7)) } +| LABEL uident COLON expr + { mk_expr (Elabel ($2, $4)) } +| WHILE expr DO loop_annotation expr DONE + { mk_expr + (Etry + (mk_expr + (Eloop ($4, + mk_expr (Eif ($2, $5, + mk_expr (Eraise (exit_exn (), None)))))), + [exit_exn (), None, mk_expr Eskip])) } +| FOR lident EQUAL expr for_direction expr DO loop_invariant expr DONE + { mk_expr (Efor ($2, $4, $5, $6, $8, $9)) } +| ABSURD + { mk_expr Eabsurd } +| expr COLON pure_type + { mk_expr (Ecast ($1, $3)) } +| RAISE uqualid + { mk_expr (Eraise ($2, None)) } +| RAISE LEFTPAR uqualid expr RIGHTPAR + { mk_expr (Eraise ($3, Some $4)) } +| TRY expr WITH bar_ list1_handler_sep_bar END + { mk_expr (Etry ($2, $5)) } +| ANY simple_type_c + { mk_expr (Eany $2) } +| LEFTPAR expr COMMA list1_expr_sep_comma RIGHTPAR + { mk_expr (Etuple ($2 :: $4)) } +; + +triple: +| pre expr post + { $1, $2, $3 } +| expr %prec prec_triple + { mk_pp PPtrue, $1, (mk_pp PPtrue, []) } +; + +simple_expr: +| constant + { mk_expr (Econstant $1) } +| qualid + { mk_expr (Eident $1) } +| LEFTPAR expr RIGHTPAR + { $2 } +| BEGIN expr END + { $2 } +| LEFTPAR RIGHTPAR + { mk_expr Eskip } +| BEGIN END + { mk_expr Eskip } +| OPPREF simple_expr + { mk_prefix $1 $2 } +; + +list1_simple_expr: +| simple_expr %prec prec_simple { [$1] } +| simple_expr list1_simple_expr { $1 :: $2 } +; + +list1_expr_sep_comma: +| expr { [$1] } +| expr COMMA list1_expr_sep_comma { $1 :: $3 } +; + +list1_handler_sep_bar: +| handler { [$1] } +| handler BAR list1_handler_sep_bar { $1 :: $3 } +; + +handler: +| uqualid ARROW expr { ($1, None, $3) } +| uqualid ident ARROW expr { ($1, Some $2, $4) } +| uqualid UNDERSCORE ARROW expr { ($1, Some (id_anonymous ()), $4) } +; + +program_match_cases: +| program_match_case { [$1] } +| program_match_case BAR program_match_cases { $1::$3 } +; + +program_match_case: +| pattern ARROW expr { ($1,$3) } +; + +assertion_kind: +| ASSERT { Aassert } +| ASSUME { Aassume } +| CHECK { Acheck } +; + +for_direction: +| TO { To } +| DOWNTO { Downto } +; + +loop_annotation: +| loop_invariant opt_variant { { loop_invariant = $1; loop_variant = $2 } } +; + +loop_invariant: +| INVARIANT annotation { Some $2 } +| /* epsilon */ { None } +; + +/* TODO: We should be able to reuse primitive_type for pure_type +pure_type: +| primitive_type { $1 } +; +*/ + +pure_type: +| pure_type_arg_no_paren { $1 } +| lqualid pure_type_args { PPTtyapp ($2, $1) } +; + +pure_type_args: +| pure_type_arg { [$1] } +| pure_type_arg pure_type_args { $1 :: $2 } +; + +pure_type_arg: +| LEFTPAR pure_type RIGHTPAR { $2 } +| pure_type_arg_no_paren { $1 } +; + +pure_type_arg_no_paren: +| type_var + { PPTtyvar $1 } +| lqualid + { PPTtyapp ([], $1) } +| LEFTPAR pure_type COMMA list1_pure_type_sep_comma RIGHTPAR + { PPTtuple ($2 :: $4) } +| LEFTPAR RIGHTPAR + { PPTtuple ([]) } +; + +list1_pure_type_sep_comma: +| pure_type { [$1] } +| pure_type COMMA list1_pure_type_sep_comma { $1 :: $3 } +; + +list1_type_v_binder: +| type_v_binder { $1 } +| type_v_binder list1_type_v_binder { $1 @ $2 } +; + +type_v_binder: +| lident labels + { [add_lab $1 $2, None] } +| LEFTPAR RIGHTPAR + { [id_anonymous (), Some (ty_unit ())] } +| LEFTPAR lidents_lab COLON type_v RIGHTPAR + { List.map (fun i -> (i, Some $4)) $2 } +; + +lidents_lab: +| lident labels list0_lident_labels { add_lab $1 $2 :: $3 } +; + +type_v: +| simple_type_v + { $1 } +| simple_type_v ARROW type_c + { Tarrow ([id_anonymous (), Some $1], $3) } +| lident labels COLON simple_type_v ARROW type_c + { Tarrow ([add_lab $1 $2, Some $4], $6) } + /* TODO: we could alllow lidents instead, e.g. x y : int -> ... */ + /*{ Tarrow (List.map (fun x -> x, Some $3) $1, $5) }*/ +; + +simple_type_v: +| pure_type + { Tpure $1 } +| LEFTPAR type_v RIGHTPAR + { $2 } +; + +type_c: +| type_v + { type_c (mk_pp PPtrue) $1 empty_effect (mk_pp PPtrue, []) } +| pre type_v effects post + { type_c $1 $2 $3 $4 } +; + +/* for ANY */ +simple_type_c: +| pure_type + { type_c (mk_pp PPtrue) (Tpure $1) empty_effect (mk_pp PPtrue, []) } +| LEFTPAR type_v RIGHTPAR + { type_c (mk_pp PPtrue) $2 empty_effect (mk_pp PPtrue, []) } +| pre type_v effects post + { type_c $1 $2 $3 $4 } +; + +annotation: +| LEFTBRC lexpr RIGHTBRC { $2 } +; + +pre: +| annotation { $1 } +; + +post: +| annotation list0_post_exn { $1, $2 } +; + +list0_post_exn: +| /* epsilon */ %prec prec_post { [] } +| list1_post_exn { $1 } +; + +list1_post_exn: +| post_exn %prec prec_post { [$1] } +| post_exn list1_post_exn { $1 :: $2 } +; + +post_exn: +| BAR uqualid ARROW annotation { $2, $4 } +; + +effects: +| opt_reads opt_writes opt_raises + { { pe_reads = $1; pe_writes = $2; pe_raises = $3 } } +; + +opt_reads: +| /* epsilon */ { [] } +| READS list0_lqualid { $2 } +; + +opt_writes: +| /* epsilon */ { [] } +| WRITES list0_lqualid { $2 } +; + +opt_raises: +| /* epsilon */ { [] } +| RAISES list0_uqualid { $2 } +; + +opt_variant: +| /* epsilon */ { None } +| VARIANT annotation { Some ($2, id_lt_nat ()) } +| VARIANT annotation WITH lqualid { Some ($2, $4) } +; + +opt_cast: +| /* epsilon */ { None } +| COLON pure_type { Some $2 } +; + +list0_lqualid: +| /* epsilon */ { [] } +| list1_lqualid { $1 } +; + +list1_lqualid: +| lqualid { [$1] } +| lqualid list1_lqualid { $1 :: $2 } +; + +list0_uqualid: +| /* epsilon */ { [] } +| list1_uqualid { $1 } +; + +list1_uqualid: +| uqualid { [$1] } +| uqualid list1_uqualid { $1 :: $2 } +; + +/* +Local Variables: +compile-command: "unset LANG; make -C ../.." +End: +*/ diff --git a/src/parser/ptree.ml b/src/parser/ptree.ml index b1909e90f46f127b5cdd1efbad9975fe236ef66c..ad25e6feae49ef5e96923e9ad8806ce2f6580ca0 100644 --- a/src/parser/ptree.ml +++ b/src/parser/ptree.ml @@ -148,3 +148,95 @@ type decl = | UseClone of loc * use * clone_subst list option | Meta of loc * ident * metarg list + +(* program files *) + +type assertion_kind = Aassert | Aassume | Acheck + +type lazy_op = LazyAnd | LazyOr + +type variant = lexpr * qualid + +type loop_annotation = { + loop_invariant : lexpr option; + loop_variant : variant option; +} + +type for_direction = To | Downto + +type effect = { + pe_reads : qualid list; + pe_writes : qualid list; + pe_raises : qualid list; +} + +type pre = lexpr + +type post = lexpr * (qualid * lexpr) list + +type type_v = + | Tpure of pty + | Tarrow of binder list * type_c + +and type_c = + { pc_result_type : type_v; + pc_effect : effect; + pc_pre : pre; + pc_post : post; } + +and binder = ident * type_v option + +type expr = { + expr_desc : expr_desc; + expr_loc : loc; +} + +and expr_desc = + (* lambda-calculus *) + | Econstant of constant + | Eident of qualid + | Eapply of expr * expr + | Efun of binder list * triple + | Elet of ident * expr * expr + | Eletrec of (ident * binder list * variant option * triple) list * expr + | Etuple of expr list + (* control *) + | Esequence of expr * expr + | Eif of expr * expr * expr + | Eloop of loop_annotation * expr + | Elazy of lazy_op * expr * expr + | Ematch of expr * (pattern * expr) list + | Eskip + | Eabsurd + | Eraise of qualid * expr option + | Etry of expr * (qualid * ident option * expr) list + | Efor of ident * expr * for_direction * expr * lexpr option * expr + (* annotations *) + | Eassert of assertion_kind * lexpr + | Elabel of ident * expr + | Ecast of expr * pty + | Eany of type_c + + (* TODO: ghost *) + +and triple = pre * expr * post + +type program_decl = + | Dlet of ident * expr + | Dletrec of (ident * binder list * variant option * triple) list + | Dlogic of decl + | Dparam of ident * type_v + | Dexn of ident * pty option + (* modules *) + | Duse of qualid * imp_exp * (*as:*) ident option + | Dnamespace of ident * (* import: *) bool * program_decl list + | Dmutable_type of ident * ident list * pty option + +type module_ = { + mod_name : ident; + mod_labels : Ident.label list; + mod_decl : program_decl list; +} + +type program_file = module_ list + diff --git a/theories/programs.why b/theories/programs.why index fbb50515adfc1e66dca452a2623f977722c31a7c..78ec6dcea4460cf5c932d6b73f0da5ea10ceac0a 100644 --- a/theories/programs.why +++ b/theories/programs.why @@ -6,8 +6,8 @@ theory Prelude type unit = () logic ignore 'a : unit - type label - logic at 'a label : 'a + (* type label *) + (* logic at 'a label : 'a *) logic old 'a : 'a type exn