Add basic support for starting ocaml repl with infer code

Summary: Make it possible to run infer code from within `ocaml`/`utop`. Integration is really basic, but we can extend it if we find it useful.

Reviewed By: jberdine

Differential Revision: D3736029

fbshipit-source-id: 4cebb7c
master
Andrzej Kotulski 8 years ago committed by Facebook Github Bot 4
parent c2ca6a23d5
commit a31c5416b1

1
.gitignore vendored

@ -87,6 +87,7 @@ buck-out/
/infer/lib/specs/clean_models /infer/lib/specs/clean_models
/scripts/checkCopyright /scripts/checkCopyright
/infer/etc/clang_ast.dict /infer/etc/clang_ast.dict
/infer/src/toplevel.mlpack
#atdgen stubs #atdgen stubs
/infer/src/backend/jsonbug_* /infer/src/backend/jsonbug_*

@ -125,7 +125,10 @@ check_missing_mli:
for x in `find infer/src -name "*.ml"`; do \ for x in `find infer/src -name "*.ml"`; do \
test -f "$$x"i || echo Missing "$$x"i; done' test -f "$$x"i || echo Missing "$$x"i; done'
test: test_build ocaml_unit_test buck_test inferTraceBugs_test inferScriptMode_test: toplevel
INFER_REPL_BINARY=ocaml ./scripts/infer_repl ./infer/tests/repl/infer_batch_script.ml
test: test_build ocaml_unit_test buck_test inferTraceBugs_test inferScriptMode_test
$(MAKE) -C $(SRC_DIR) mod_dep.dot $(MAKE) -C $(SRC_DIR) mod_dep.dot
test_xml: test_build ocaml_unit_test buck_test_xml inferTraceBugs_test test_xml: test_build ocaml_unit_test buck_test_xml inferTraceBugs_test
@ -133,6 +136,9 @@ test_xml: test_build ocaml_unit_test buck_test_xml inferTraceBugs_test
quick-test: test_this_build ocaml_unit_test quick-test: test_this_build ocaml_unit_test
toplevel:
$(MAKE) -C $(SRC_DIR) toplevel
uninstall: uninstall:
$(REMOVE_DIR) $(DESTDIR)$(libdir)/infer/ $(REMOVE_DIR) $(DESTDIR)$(libdir)/infer/
$(REMOVE) $(DESTDIR)$(bindir)/inferTraceBugs $(REMOVE) $(DESTDIR)$(bindir)/inferTraceBugs
@ -274,7 +280,7 @@ conf-clean: clean
.PHONY: all buck_test buck_test_xml clean clang_plugin clang_setup infer inferTraceBugs .PHONY: all buck_test buck_test_xml clean clang_plugin clang_setup infer inferTraceBugs
.PHONY: inferTraceBugs_test install ocaml_unit_test check_missing_mli src_build test test_xml .PHONY: inferTraceBugs_test install ocaml_unit_test check_missing_mli src_build test test_xml
.PHONY: test_build uninstall .PHONY: test_build toplevel uninstall
# print any variable for Makefile debugging # print any variable for Makefile debugging

@ -169,7 +169,7 @@ INFER_CONFIG_TARGETS += $(INFERLLVM_MAIN).native
DEPENDENCIES += llvm DEPENDENCIES += llvm
endif endif
.PHONY: all infer init version sanitize clean .PHONY: all infer init version sanitize clean toplevel
all: infer all: infer
@ -251,6 +251,27 @@ mod_dep.dot: $(DEPENDENCIES_DIR)/ocamldot/ocamldot $(ml_src_files) $(re_src_file
mod_dep.pdf: mod_dep.dot mod_dep.pdf: mod_dep.dot
dot -Tpdf -o mod_dep.pdf mod_dep.dot dot -Tpdf -o mod_dep.pdf mod_dep.dot
roots_grep_regex:=$(foreach root,$(roots),-e $(root)$$)
dirs_find_regex:=$(foreach dir, $(DEPENDENCIES),-path "./$(dir)/*" -o)
toplevel: init $(STACKTREE_ATDGEN_STUBS) $(INFERPRINT_ATDGEN_STUBS) $(CLANG_ATDGEN_STUBS) $(INFER_CLANG_FCP_MIRRORED_FILES)
# We need to pack all infer modules into another module to avoid name clashes
# with some of them coming from ocaml libraries (Ident for example).
# To do that, we generate .mlpack file with source files. Steps:
# 1. find all interesting .re and .ml files - they need to be in one of
# directories listed in $(DEPENDENCIES)
# 2. remove './' from the beginning of each line
# 3. remove extension from all files
# 4. make first letter of filename uppercase to produce valid ocaml module
# 5. filter out root modules since they run code when loading the module.
find . \( -name "*.ml" -o -name "*.mly" -o -name "*.mll" -o -name "*.re" \) \
\( $(dirs_find_regex) -false \) \
-not \( -path "./unit/*" -o -path "./llvm/*" -o -path "./facebook/scripts/eradicate_stats.ml" \) \
| cut -c 3- \
| rev | cut -f 2- -d '.' | rev \
| awk 'BEGIN { FS = "/"; OFS = "/" } ; {$$NF=toupper(substr($$NF,1,1))substr($$NF,2); print $$0}' \
| grep -v $(roots_grep_regex) > toplevel.mlpack
$(OCAMLBUILD_ALL) -build-dir $(INFER_BUILD_DIR) toplevel.cmo
define gen_atdgen_rules define gen_atdgen_rules
# generate files using atdgen # generate files using atdgen
# parameters: # parameters:

@ -17,7 +17,7 @@ module YBU = Yojson.Basic.Util
(** Each command line option may appear in the --help list of any executable, these tags are used to (** Each command line option may appear in the --help list of any executable, these tags are used to
specify which executables for which an option will be documented. *) specify which executables for which an option will be documented. *)
type exe = Analyze | Clang | Java | Llvm | Print | StatsAggregator | Toplevel type exe = Analyze | Clang | Java | Llvm | Print | StatsAggregator | Toplevel | Interactive
let exes = [ let exes = [
("InferAnalyze", Analyze); ("InferAnalyze", Analyze);
@ -27,13 +27,16 @@ let exes = [
("InferPrint", Print); ("InferPrint", Print);
("InferStatsAggregator", StatsAggregator); ("InferStatsAggregator", StatsAggregator);
("infer", Toplevel); ("infer", Toplevel);
("interactive", Interactive);
] ]
let all_exes = IList.map snd exes let all_exes = IList.map snd exes
let current_exe = let current_exe =
try IList.assoc string_equal (Filename.basename Sys.executable_name) exes if !Sys.interactive then Interactive
with Not_found -> Toplevel else
try IList.assoc string_equal (Filename.basename Sys.executable_name) exes
with Not_found -> Toplevel
type desc = { type desc = {
@ -442,7 +445,7 @@ let decode_env_to_argv env =
let prepend_to_argv args = let prepend_to_argv args =
let cl_args = match Array.to_list Sys.argv with _ :: tl -> tl | [] -> [] in let cl_args = match Array.to_list Sys.argv with _ :: tl -> tl | [] -> [] in
(Sys.executable_name, args @ cl_args) args @ cl_args
(** [prefix_before_rest (prefix @ ["--" :: rest])] is [prefix] where "--" is not in [prefix]. *) (** [prefix_before_rest (prefix @ ["--" :: rest])] is [prefix] where "--" is not in [prefix]. *)
let prefix_before_rest args = let prefix_before_rest args =
@ -553,7 +556,10 @@ let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var exe_u
(try Unix.getenv "INFERCLANG_ARGS" with Not_found -> "") in (try Unix.getenv "INFERCLANG_ARGS" with Not_found -> "") in
let env_args = c_args @ env_args in let env_args = c_args @ env_args in
(* end transitional support for INFERCLANG_ARGS *) (* end transitional support for INFERCLANG_ARGS *)
let exe_name, env_cl_args = prepend_to_argv env_args in let exe_name = Sys.executable_name in
let env_cl_args = match current_exe with
| Interactive -> env_args
| _ -> prepend_to_argv env_args in
let all_args = match config_file with let all_args = match config_file with
| None -> env_cl_args | None -> env_cl_args
| Some path -> | Some path ->
@ -575,7 +581,7 @@ let parse ?(incomplete=false) ?(accept_unknown=false) ?config_file env_var exe_u
| Arg.Bad usage_msg -> Pervasives.prerr_string usage_msg; exit 2 | Arg.Bad usage_msg -> Pervasives.prerr_string usage_msg; exit 2
| Arg.Help usage_msg -> Pervasives.print_string usage_msg; exit 0 | Arg.Help usage_msg -> Pervasives.print_string usage_msg; exit 0
in in
parse_loop () ; parse_loop ();
if not incomplete then if not incomplete then
Unix.putenv env_var (encode_argv_to_env (prefix_before_rest all_args)) ; Unix.putenv env_var (encode_argv_to_env (prefix_before_rest all_args)) ;
curr_usage curr_usage

@ -11,7 +11,7 @@
open! Utils open! Utils
type exe = Analyze | Clang | Java | Llvm | Print | StatsAggregator | Toplevel type exe = Analyze | Clang | Java | Llvm | Print | StatsAggregator | Toplevel | Interactive
val current_exe : exe val current_exe : exe

@ -1183,6 +1183,8 @@ let exe_usage (exe : CLOpt.exe) =
Aggregates all the perf stats generated by Buck on each target" Aggregates all the perf stats generated by Buck on each target"
| Toplevel -> | Toplevel ->
version_string version_string
| Interactive ->
"Usage: interactive ocaml toplevel. To pass infer config options use env variable"
let post_parsing_initialization () = let post_parsing_initialization () =
F.set_margin !margin ; F.set_margin !margin ;

@ -0,0 +1,22 @@
(*
* Copyright (c) 2016 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
(* Example of ocaml script starting with infer code. To execute a scipt run:
./scripts/infer_repl <path/to/this/script.ml>
It's used as a basic integration test *)
(* "import" infer code *)
#use "toplevel_init";;
let _ = Ident.create_fresh Ident.knormal in
let ident = Ident.create_fresh Ident.knormal in
let e = Exp.Var ident in
print_endline (Sil.exp_to_string e);
(* pass --flavors flag to change the value *)
print_endline (string_of_bool Config.flavors)

@ -0,0 +1,20 @@
#!/bin/bash
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
BUILD_DIR=$SCRIPT_DIR/../infer/_build/infer
# to build new toplevel, run `make toplevel`
# -init option is used only in interactive mode
# in batch mode, scripts need to import toplevel_init themselves
# It can be done by adding #use "toplevel_init";; to the beginning
# of a script.
# NOTE: $SCRIPT_DIR is added search path for batch scripts
# so they can be located anywhere and still find toplevel_init
# file. In interactive mode $SCRIPT_DIR isn't needed
# by default utop is used, pass `INFER_UTOP_BINARY` to change the toplevel
# binary (to `ocaml` for example)
if [ -z "$INFER_UTOP_BINARY" ]; then
INFER_REPL_BINARY="utop"
fi
$INFER_REPL_BINARY -init $SCRIPT_DIR/toplevel_init -I $BUILD_DIR -I $SCRIPT_DIR $@

@ -0,0 +1,9 @@
(* load dependencies *)
#use "topfind";;
#require "sawja";;
#require "atdgen";;
#require "extlib";;
(* load infer code *)
#load_rec "toplevel.cmo";;
open Toplevel;;
Loading…
Cancel
Save