Skip to content

Commit c673844

Browse files
amosramosr-msft
authored andcommitted
add --lang_extension pulse flag for file extensions
This adds a new command-line argument `--lang_extension ...` which allows F* to recognise and look for files with the given file extension. The language extension must be separately loaded with --load_cmxs or else be available on the include path.
1 parent 8394ee3 commit c673844

File tree

5 files changed

+149
-81
lines changed

5 files changed

+149
-81
lines changed

src/basic/FStarC.Options.fst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ let defaults = [
234234
("initial_ifuel" , Int 1);
235235
("keep_query_captions" , Bool true);
236236
("krmloutput" , Unset);
237+
("lang_extensions" , List []);
237238
("lax" , Bool false);
238239
("list_plugins" , Bool false);
239240
("load_cmxs" , List []);
@@ -500,6 +501,7 @@ let get_print_in_place () = lookup_opt "print_in_place"
500501
let get_initial_fuel () = lookup_opt "initial_fuel" as_int
501502
let get_initial_ifuel () = lookup_opt "initial_ifuel" as_int
502503
let get_keep_query_captions () = lookup_opt "keep_query_captions" as_bool
504+
let get_lang_extensions () = lookup_opt "lang_extensions" (as_list as_string)
503505
let get_lax () = lookup_opt "lax" as_bool
504506
let get_load () = lookup_opt "load" (as_list as_string)
505507
let get_load_cmxs () = lookup_opt "load_cmxs" (as_list as_string)
@@ -1117,6 +1119,11 @@ let specs_with_types warn_unsafe : list (char & string & opt_type & Pprint.docum
11171119
BoolStr,
11181120
text "Retain comments in the logged SMT queries (requires --log_queries or --log_failing_queries; default true)");
11191121
1122+
( noshort,
1123+
"lang_extensions",
1124+
Accumulated (SimpleStr "extension"),
1125+
text "Automatically enable the given language extensions based on the file extension; the language extension's .cmxs must be on the include path or loaded with --load_cmxs");
1126+
11201127
( noshort,
11211128
"lax",
11221129
WithSideEffect ((fun () -> if warn_unsafe then option_warning_callback "lax"), Const (Bool true)),
@@ -1762,6 +1769,7 @@ let settable = function
17621769
| "initial_ifuel"
17631770
| "ide_id_info_off"
17641771
| "keep_query_captions"
1772+
| "lang_extensions"
17651773
| "load"
17661774
| "load_cmxs"
17671775
| "log_queries"
@@ -2118,6 +2126,7 @@ let print () = get_print ()
21182126
let print_in_place () = get_print_in_place ()
21192127
let initial_fuel () = min (get_initial_fuel ()) (get_max_fuel ())
21202128
let initial_ifuel () = min (get_initial_ifuel ()) (get_max_ifuel ())
2129+
let lang_extensions () = get_lang_extensions ()
21212130
let lax () = get_lax ()
21222131
let load () = get_load ()
21232132
let load_cmxs () = get_load_cmxs ()

src/basic/FStarC.Options.fsti

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ val initial_fuel : unit -> int
161161
val initial_ifuel : unit -> int
162162
val interactive : unit -> bool
163163
val keep_query_captions : unit -> bool
164+
val lang_extensions : unit -> list string
164165
val lax : unit -> bool
165166
val load : unit -> list string
166167
val load_cmxs : unit -> list string

src/ml/FStarC_Parser_ParseIt.ml

Lines changed: 132 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,19 @@ let read_file (filename:string) =
7676
if debug then FStarC_Format.print1 "Opening file %s\n" filename;
7777
filename, read_physical_file filename
7878

79-
let fst_extensions = [".fst"; ".fsti"]
80-
let interface_extensions = [".fsti"]
79+
let extra_extensions () = List.concat_map (fun x -> ["." ^ x; "." ^ x ^ "i"]) (FStarC_Options.lang_extensions ())
80+
let fst_extensions () = [".fst"; ".fsti"] @ extra_extensions ()
81+
let extra_extensions_interface () = List.map (fun x -> "." ^ x ^ "i") (FStarC_Options.lang_extensions ())
82+
let interface_extensions () = [".fsti"] @ extra_extensions_interface ()
8183

8284
let has_extension file extensions =
8385
FStar_List.existsb (U.ends_with file) extensions
8486

87+
let take_lang_extension file =
88+
FStar_List.tryFind (fun x -> U.ends_with file ("."^x)) (FStarC_Options.lang_extensions ())
89+
8590
let check_extension fn =
86-
if (not (has_extension fn fst_extensions)) then
91+
if (not (has_extension fn (fst_extensions ()))) then
8792
let message = FStarC_Format.fmt1 "Unrecognized extension '%s'" fn in
8893
raise_error_text FStarC_Range.dummyRange Fatal_UnrecognizedExtension message
8994

@@ -522,92 +527,142 @@ let _ = FStarC_Parser_AST_Util.register_extension_lang_parser "fstar" parse_fsta
522527

523528
type lang_opts = string option
524529

530+
let rec insert_use_lang lang decls =
531+
match decls with
532+
| [] -> []
533+
| { FStarC_Parser_AST.d = FStarC_Parser_AST.TopLevelModule _ } as d ::ds ->
534+
let use_lang =
535+
{ d with FStarC_Parser_AST.d = FStarC_Parser_AST.UseLangDecls lang; }
536+
in
537+
d :: use_lang :: ds
538+
| d::ds ->
539+
d :: insert_use_lang lang ds
540+
525541
let parse_lang lang fn =
526-
match fn with
527-
| Filename _ ->
528-
failwith "parse_lang: only in incremental mode"
529-
| Incremental s
530-
| Toplevel s
531-
| Fragment s ->
532-
try
533-
let frag_pos = FStarC_Range.mk_pos s.frag_line s.frag_col in
534-
let rng = FStarC_Range.mk_range s.frag_fname frag_pos frag_pos in
535-
let decls = FStarC_Parser_AST_Util.parse_extension_lang lang s.frag_text rng in
536-
let comments = FStarC_Parser_Util.flush_comments () in
537-
ASTFragment (Inr decls, comments)
538-
with
542+
let frag =
543+
match fn with
544+
| Filename f ->
545+
check_extension f;
546+
let f', contents = read_file f in
547+
{
548+
frag_fname = f';
549+
frag_text = contents;
550+
frag_line = Z.one;
551+
frag_col = Z.zero;
552+
}
553+
| Incremental frag
554+
| Toplevel frag
555+
| Fragment frag -> frag
556+
in
557+
try
558+
let frag_pos = FStarC_Range.mk_pos frag.frag_line frag.frag_col in
559+
let rng = FStarC_Range.mk_range frag.frag_fname frag_pos frag_pos in
560+
let contents_at = contents_at frag.frag_text in
561+
let decls = FStarC_Parser_AST_Util.parse_extension_lang lang frag.frag_text rng in
562+
let decls = insert_use_lang lang decls in
563+
let comments = FStarC_Parser_Util.flush_comments () in
564+
match fn with
565+
| Filename _ | Toplevel _ ->
566+
ASTFragment (FStarC_Parser_AST.as_frag decls, comments)
567+
| Incremental _ ->
568+
let decls = List.map (fun d -> d, contents_at d.FStarC_Parser_AST.drange) decls in
569+
IncrementalFragment (decls, comments, None)
570+
| Fragment _ ->
571+
(* parse_no_lang returns `Term` for Fragment, but we don't have a term parser for language extensions *)
572+
ASTFragment (FStar_Pervasives.Inr decls, comments)
573+
with
574+
| FStarC_Errors.Error(e, msg, r, _ctx) ->
575+
ParseError (e, msg, r)
576+
577+
let parse_no_lang fn =
578+
let lexbuf, filename, contents =
579+
match fn with
580+
| Filename f ->
581+
check_extension f;
582+
let f', contents = read_file f in
583+
(try create contents f' 1 0, f', contents
584+
with _ -> raise_error_text FStarC_Range.dummyRange Fatal_InvalidUTF8Encoding (FStarC_Format.fmt1 "File %s has invalid UTF-8 encoding." f'))
585+
| Incremental s
586+
| Toplevel s
587+
| Fragment s ->
588+
create s.frag_text s.frag_fname (Z.to_int s.frag_line) (Z.to_int s.frag_col), "<input>", s.frag_text
589+
in
590+
591+
let lexer () =
592+
let tok = FStarC_Parser_LexFStar.token lexbuf in
593+
if !dbg_Tokens then
594+
print_string ("TOKEN: " ^ (string_of_token tok) ^ "\n");
595+
(tok, lexbuf.start_p, lexbuf.cur_p)
596+
in
597+
try
598+
match fn with
599+
| Filename _
600+
| Toplevel _ -> begin
601+
let fileOrFragment =
602+
MenhirLib.Convert.Simplified.traditional2revised FStarC_Parser_Parse.inputFragment lexer
603+
in
604+
let frags = match fileOrFragment with
605+
| FStar_Pervasives.Inl modul ->
606+
if has_extension filename (interface_extensions ())
607+
then FStar_Pervasives.Inl (FStarC_Parser_AST.as_interface modul)
608+
else FStar_Pervasives.Inl modul
609+
| _ -> fileOrFragment
610+
in ASTFragment (frags, FStarC_Parser_Util.flush_comments ())
611+
end
612+
613+
| Incremental i ->
614+
let decls, comments, err_opt =
615+
parse_incremental_fragment
616+
filename
617+
i.frag_text
618+
lexbuf
619+
lexer
620+
(fun (d:FStarC_Parser_AST.decl) -> d.drange)
621+
FStarC_Parser_Parse.oneDeclOrEOF
622+
in
623+
IncrementalFragment(decls, comments, err_opt)
624+
625+
| Fragment _ ->
626+
Term (MenhirLib.Convert.Simplified.traditional2revised FStarC_Parser_Parse.term lexer)
627+
with
628+
| FStarC_Errors.Empty_frag ->
629+
ASTFragment (FStar_Pervasives.Inr [], [])
630+
539631
| FStarC_Errors.Error(e, msg, r, _ctx) ->
540632
ParseError (e, msg, r)
541633

634+
| e ->
635+
(*
636+
| Parsing.Parse_error as _e
637+
| FStarC_Parser_Parse.MenhirBasics.Error as _e ->
638+
*)
639+
ParseError (err_of_parse_error filename lexbuf None)
640+
641+
542642
let parse (lang_opt:lang_opts) fn =
543643
FStarC_Stats.record "parse" @@ fun () ->
544644
FStarC_Parser_Util.warningHandler := (function
545645
| e -> Printf.printf "There was some warning (TODO)\n");
646+
546647
match lang_opt with
547648
| Some lang -> parse_lang lang fn
548-
| _ ->
549-
let lexbuf, filename, contents =
550-
match fn with
551-
| Filename f ->
552-
check_extension f;
553-
let f', contents = read_file f in
554-
(try create contents f' 1 0, f', contents
555-
with _ -> raise_error_text FStarC_Range.dummyRange Fatal_InvalidUTF8Encoding (FStarC_Format.fmt1 "File %s has invalid UTF-8 encoding." f'))
556-
| Incremental s
557-
| Toplevel s
558-
| Fragment s ->
559-
create s.frag_text s.frag_fname (Z.to_int s.frag_line) (Z.to_int s.frag_col), "<input>", s.frag_text
649+
| None ->
650+
let filename =
651+
match fn with
652+
| Filename fn -> fn
653+
| Toplevel frag -> frag.frag_fname
654+
| Incremental frag -> frag.frag_fname
655+
| Fragment frag -> frag.frag_fname
560656
in
561-
562-
let lexer () =
563-
let tok = FStarC_Parser_LexFStar.token lexbuf in
564-
if !dbg_Tokens then
565-
print_string ("TOKEN: " ^ (string_of_token tok) ^ "\n");
566-
(tok, lexbuf.start_p, lexbuf.cur_p)
657+
let filename =
658+
(* If in IDE mode, the IDE filename takes precedence as frag_fname might be "<input>" *)
659+
if FStarC_Options.ide ()
660+
then Option.value ~default:filename (FStarC_Options.ide_filename ())
661+
else filename
567662
in
568-
try
569-
match fn with
570-
| Filename _
571-
| Toplevel _ -> begin
572-
let fileOrFragment =
573-
MenhirLib.Convert.Simplified.traditional2revised FStarC_Parser_Parse.inputFragment lexer
574-
in
575-
let frags = match fileOrFragment with
576-
| FStar_Pervasives.Inl modul ->
577-
if has_extension filename interface_extensions
578-
then FStar_Pervasives.Inl (FStarC_Parser_AST.as_interface modul)
579-
else FStar_Pervasives.Inl modul
580-
| _ -> fileOrFragment
581-
in ASTFragment (frags, FStarC_Parser_Util.flush_comments ())
582-
end
583-
584-
| Incremental i ->
585-
let decls, comments, err_opt =
586-
parse_incremental_fragment
587-
filename
588-
i.frag_text
589-
lexbuf
590-
lexer
591-
(fun (d:FStarC_Parser_AST.decl) -> d.drange)
592-
FStarC_Parser_Parse.oneDeclOrEOF
593-
in
594-
IncrementalFragment(decls, comments, err_opt)
595-
596-
| Fragment _ ->
597-
Term (MenhirLib.Convert.Simplified.traditional2revised FStarC_Parser_Parse.term lexer)
598-
with
599-
| FStarC_Errors.Empty_frag ->
600-
ASTFragment (FStar_Pervasives.Inr [], [])
601-
602-
| FStarC_Errors.Error(e, msg, r, _ctx) ->
603-
ParseError (e, msg, r)
604-
605-
| e ->
606-
(*
607-
| Parsing.Parse_error as _e
608-
| FStarC_Parser_Parse.MenhirBasics.Error as _e ->
609-
*)
610-
ParseError (err_of_parse_error filename lexbuf None)
663+
match take_lang_extension filename with
664+
| Some lang -> parse_lang lang fn
665+
| None -> parse_no_lang fn
611666

612667

613668
(** Parsing of command-line error/warning/silent flags. *)

src/parser/FStarC.Parser.Dep.fst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,20 @@ let files_for_module_name_to_string (m:files_for_module_name) =
8787

8888
type color = | White | Gray | Black
8989

90+
let all_file_suffixes () =
91+
let lang_exts = List.map (fun ext -> "." ^ ext) (FStarC.Options.lang_extensions ()) in
92+
let base = ".fst" :: lang_exts in
93+
base @ List.map (fun ext -> ext ^ "i") base
94+
9095
let check_and_strip_suffix (f: string): option string =
91-
let suffixes = [ ".fsti"; ".fst" ] in
9296
let matches = List.map (fun ext ->
9397
let lext = String.length ext in
9498
let l = String.length f in
9599
if l > lext && String.substring f (l - lext) lext = ext then
96100
Some (String.substring f 0 (l - lext))
97101
else
98102
None
99-
) suffixes in
103+
) (all_file_suffixes ()) in
100104
match List.filter Some? matches with
101105
| Some m :: _ ->
102106
Some m
@@ -1442,7 +1446,7 @@ let all_files_in_include_paths () =
14421446
List.collect
14431447
(fun path ->
14441448
let files = safe_readdir_for_include path in
1445-
let files = List.filter (fun f -> Util.ends_with f ".fst" || Util.ends_with f ".fsti") files in
1449+
let files = List.filter (fun f -> List.existsb (fun ext -> Util.ends_with f ext) (all_file_suffixes ())) files in
14461450
List.map (fun file -> Filepath.join_paths path file) files)
14471451
paths
14481452

src/syntax/FStarC.Syntax.DsEnv.fst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1614,7 +1614,6 @@ let inclusion_info env (l:lident) =
16141614

16151615
let prepare_module_or_interface intf admitted env mname (mii:module_inclusion_info) = (* AR: open the pervasives namespace *)
16161616
let prep env =
1617-
let filename = BU.strcat (string_of_lid mname) ".fst" in
16181617
let auto_open = if mii.mii_no_prelude then [] else FStarC.Parser.Dep.prelude in
16191618
let auto_open =
16201619
let convert_kind = function

0 commit comments

Comments
 (0)