summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.depend297
-rw-r--r--.gitignore6
-rw-r--r--Changes4
-rw-r--r--Makefile20
-rw-r--r--compilerlibs/Makefile.compilerlibs22
-rw-r--r--testsuite/tests/tool-toplevel/pr6468.compilers.reference2
-rw-r--r--tools/.depend2
-rw-r--r--toplevel/byte/topeval.ml356
-rw-r--r--toplevel/byte/toploop.ml649
-rw-r--r--toplevel/byte/topmain.ml114
-rw-r--r--toplevel/byte/trace.ml3
-rw-r--r--toplevel/dune4
-rw-r--r--toplevel/native/topdirs.ml224
-rw-r--r--toplevel/native/topeval.ml (renamed from toplevel/native/toploop.ml)430
-rw-r--r--toplevel/native/topmain.ml26
-rw-r--r--toplevel/topcommon.ml302
-rw-r--r--toplevel/topcommon.mli198
-rw-r--r--toplevel/topdirs.ml (renamed from toplevel/byte/topdirs.ml)233
-rw-r--r--toplevel/topdirs.mli18
-rw-r--r--toplevel/topeval.mli56
-rw-r--r--toplevel/toploop.ml202
-rw-r--r--toplevel/toploop.mli16
22 files changed, 1537 insertions, 1647 deletions
diff --git a/.depend b/.depend
index 8f46de8fb3..df50d9483b 100644
--- a/.depend
+++ b/.depend
@@ -6118,41 +6118,76 @@ toplevel/genprintval.cmi : \
typing/path.cmi \
typing/outcometree.cmi \
typing/env.cmi
-toplevel/topdirs.cmi : \
- parsing/longident.cmi
-toplevel/toploop.cmi : \
- utils/warnings.cmi \
+toplevel/topcommon.cmo : \
typing/types.cmi \
+ parsing/printast.cmi \
+ typing/predef.cmi \
+ parsing/pprintast.cmi \
+ driver/pparse.cmi \
typing/path.cmi \
parsing/parsetree.cmi \
+ parsing/parse.cmi \
typing/outcometree.cmi \
+ typing/oprint.cmi \
+ utils/misc.cmi \
parsing/longident.cmi \
parsing/location.cmi \
- typing/env.cmi
-toplevel/topmain.cmi :
-toplevel/topstart.cmo : \
- toplevel/topmain.cmi
-toplevel/topstart.cmx : \
- toplevel/topmain.cmi
-toplevel/trace.cmi : \
+ utils/load_path.cmi \
+ parsing/lexer.cmi \
+ toplevel/genprintval.cmi \
+ typing/env.cmi \
+ bytecomp/dll.cmi \
+ utils/config.cmi \
+ driver/compmisc.cmi \
+ driver/compenv.cmi \
+ utils/clflags.cmi \
+ parsing/ast_helper.cmi \
+ toplevel/topcommon.cmi
+toplevel/topcommon.cmx : \
+ typing/types.cmx \
+ parsing/printast.cmx \
+ typing/predef.cmx \
+ parsing/pprintast.cmx \
+ driver/pparse.cmx \
+ typing/path.cmx \
+ parsing/parsetree.cmi \
+ parsing/parse.cmx \
+ typing/outcometree.cmi \
+ typing/oprint.cmx \
+ utils/misc.cmx \
+ parsing/longident.cmx \
+ parsing/location.cmx \
+ utils/load_path.cmx \
+ parsing/lexer.cmx \
+ toplevel/genprintval.cmx \
+ typing/env.cmx \
+ bytecomp/dll.cmx \
+ utils/config.cmx \
+ driver/compmisc.cmx \
+ driver/compenv.cmx \
+ utils/clflags.cmx \
+ parsing/ast_helper.cmx \
+ toplevel/topcommon.cmi
+toplevel/topcommon.cmi : \
+ utils/warnings.cmi \
typing/types.cmi \
typing/path.cmi \
+ parsing/parsetree.cmi \
+ typing/outcometree.cmi \
parsing/longident.cmi \
+ parsing/location.cmi \
+ toplevel/genprintval.cmi \
typing/env.cmi
-toplevel/byte/topdirs.cmo : \
+toplevel/topdirs.cmo : \
utils/warnings.cmi \
typing/types.cmi \
- toplevel/byte/trace.cmi \
- toplevel/byte/toploop.cmi \
- bytecomp/symtable.cmi \
+ toplevel/toploop.cmi \
+ toplevel/topeval.cmi \
typing/printtyp.cmi \
typing/predef.cmi \
- typing/persistent_env.cmi \
typing/path.cmi \
parsing/parsetree.cmi \
- bytecomp/opcodes.cmi \
utils/misc.cmi \
- bytecomp/meta.cmi \
parsing/longident.cmi \
parsing/location.cmi \
utils/load_path.cmi \
@@ -6162,26 +6197,21 @@ toplevel/byte/topdirs.cmo : \
typing/ctype.cmi \
utils/config.cmi \
driver/compenv.cmi \
- file_formats/cmo_format.cmi \
utils/clflags.cmi \
typing/btype.cmi \
parsing/asttypes.cmi \
parsing/ast_helper.cmi \
- toplevel/byte/topdirs.cmi
-toplevel/byte/topdirs.cmx : \
+ toplevel/topdirs.cmi
+toplevel/topdirs.cmx : \
utils/warnings.cmx \
typing/types.cmx \
- toplevel/byte/trace.cmx \
- toplevel/byte/toploop.cmx \
- bytecomp/symtable.cmx \
+ toplevel/toploop.cmx \
+ toplevel/topeval.cmi \
typing/printtyp.cmx \
typing/predef.cmx \
- typing/persistent_env.cmx \
typing/path.cmx \
parsing/parsetree.cmi \
- bytecomp/opcodes.cmx \
utils/misc.cmx \
- bytecomp/meta.cmx \
parsing/longident.cmx \
parsing/location.cmx \
utils/load_path.cmx \
@@ -6191,43 +6221,93 @@ toplevel/byte/topdirs.cmx : \
typing/ctype.cmx \
utils/config.cmx \
driver/compenv.cmx \
- file_formats/cmo_format.cmi \
utils/clflags.cmx \
typing/btype.cmx \
parsing/asttypes.cmi \
parsing/ast_helper.cmx \
- toplevel/byte/topdirs.cmi
-toplevel/byte/topdirs.cmi : \
+ toplevel/topdirs.cmi
+toplevel/topdirs.cmi : \
parsing/longident.cmi
-toplevel/byte/toploop.cmo : \
+toplevel/topeval.cmi : \
+ toplevel/topcommon.cmi \
+ typing/path.cmi \
+ parsing/parsetree.cmi \
+ typing/env.cmi
+toplevel/toploop.cmo : \
utils/warnings.cmi \
typing/typetexp.cmi \
+ toplevel/topeval.cmi \
+ toplevel/topcommon.cmi \
+ utils/misc.cmi \
+ parsing/location.cmi \
+ utils/load_path.cmi \
+ parsing/lexer.cmi \
+ typing/env.cmi \
+ utils/config.cmi \
+ driver/compmisc.cmi \
+ driver/compenv.cmi \
+ utils/clflags.cmi \
+ typing/btype.cmi \
+ toplevel/toploop.cmi
+toplevel/toploop.cmx : \
+ utils/warnings.cmx \
+ typing/typetexp.cmx \
+ toplevel/topeval.cmi \
+ toplevel/topcommon.cmx \
+ utils/misc.cmx \
+ parsing/location.cmx \
+ utils/load_path.cmx \
+ parsing/lexer.cmx \
+ typing/env.cmx \
+ utils/config.cmx \
+ driver/compmisc.cmx \
+ driver/compenv.cmx \
+ utils/clflags.cmx \
+ typing/btype.cmx \
+ toplevel/toploop.cmi
+toplevel/toploop.cmi : \
+ utils/warnings.cmi \
+ typing/types.cmi \
+ typing/path.cmi \
+ parsing/parsetree.cmi \
+ typing/outcometree.cmi \
+ parsing/longident.cmi \
+ parsing/location.cmi \
+ typing/env.cmi
+toplevel/topmain.cmi :
+toplevel/topstart.cmo : \
+ toplevel/topmain.cmi
+toplevel/topstart.cmx : \
+ toplevel/topmain.cmi
+toplevel/trace.cmi : \
+ typing/types.cmi \
+ typing/path.cmi \
+ parsing/longident.cmi \
+ typing/env.cmi
+toplevel/byte/topeval.cmo : \
+ utils/warnings.cmi \
typing/types.cmi \
typing/typemod.cmi \
typing/typedtree.cmi \
typing/typecore.cmi \
lambda/translmod.cmi \
+ toplevel/topcommon.cmi \
bytecomp/symtable.cmi \
lambda/simplif.cmi \
typing/printtyped.cmi \
typing/printtyp.cmi \
lambda/printlambda.cmi \
bytecomp/printinstr.cmi \
- parsing/printast.cmi \
typing/predef.cmi \
- parsing/pprintast.cmi \
- driver/pparse.cmi \
+ typing/persistent_env.cmi \
typing/path.cmi \
parsing/parsetree.cmi \
- parsing/parse.cmi \
typing/outcometree.cmi \
- typing/oprint.cmi \
+ bytecomp/opcodes.cmi \
utils/misc.cmi \
bytecomp/meta.cmi \
- parsing/longident.cmi \
parsing/location.cmi \
utils/load_path.cmi \
- parsing/lexer.cmi \
typing/includemod.cmi \
typing/ident.cmi \
toplevel/genprintval.cmi \
@@ -6236,42 +6316,35 @@ toplevel/byte/toploop.cmo : \
bytecomp/dll.cmi \
utils/config.cmi \
driver/compmisc.cmi \
- driver/compenv.cmi \
+ file_formats/cmo_format.cmi \
utils/clflags.cmi \
bytecomp/bytegen.cmi \
- typing/btype.cmi \
parsing/asttypes.cmi \
- parsing/ast_helper.cmi \
- toplevel/byte/toploop.cmi
-toplevel/byte/toploop.cmx : \
+ toplevel/byte/topeval.cmi
+toplevel/byte/topeval.cmx : \
utils/warnings.cmx \
- typing/typetexp.cmx \
typing/types.cmx \
typing/typemod.cmx \
typing/typedtree.cmx \
typing/typecore.cmx \
lambda/translmod.cmx \
+ toplevel/topcommon.cmx \
bytecomp/symtable.cmx \
lambda/simplif.cmx \
typing/printtyped.cmx \
typing/printtyp.cmx \
lambda/printlambda.cmx \
bytecomp/printinstr.cmx \
- parsing/printast.cmx \
typing/predef.cmx \
- parsing/pprintast.cmx \
- driver/pparse.cmx \
+ typing/persistent_env.cmx \
typing/path.cmx \
parsing/parsetree.cmi \
- parsing/parse.cmx \
typing/outcometree.cmi \
- typing/oprint.cmx \
+ bytecomp/opcodes.cmx \
utils/misc.cmx \
bytecomp/meta.cmx \
- parsing/longident.cmx \
parsing/location.cmx \
utils/load_path.cmx \
- parsing/lexer.cmx \
typing/includemod.cmx \
typing/ident.cmx \
toplevel/genprintval.cmx \
@@ -6280,38 +6353,46 @@ toplevel/byte/toploop.cmx : \
bytecomp/dll.cmx \
utils/config.cmx \
driver/compmisc.cmx \
- driver/compenv.cmx \
+ file_formats/cmo_format.cmi \
utils/clflags.cmx \
bytecomp/bytegen.cmx \
- typing/btype.cmx \
parsing/asttypes.cmi \
- parsing/ast_helper.cmx \
- toplevel/byte/toploop.cmi
-toplevel/byte/toploop.cmi : \
- utils/warnings.cmi \
- typing/types.cmi \
+ toplevel/byte/topeval.cmi
+toplevel/byte/topeval.cmi : \
+ toplevel/topcommon.cmi \
typing/path.cmi \
parsing/parsetree.cmi \
- typing/outcometree.cmi \
- parsing/longident.cmi \
- parsing/location.cmi \
typing/env.cmi
toplevel/byte/topmain.cmo : \
- toplevel/byte/toploop.cmi \
- toplevel/byte/topdirs.cmi \
+ toplevel/byte/trace.cmi \
+ toplevel/toploop.cmi \
+ toplevel/byte/topeval.cmi \
+ toplevel/topdirs.cmi \
+ toplevel/topcommon.cmi \
+ typing/printtyp.cmi \
+ typing/path.cmi \
utils/misc.cmi \
driver/main_args.cmi \
parsing/location.cmi \
+ typing/env.cmi \
+ typing/ctype.cmi \
driver/compmisc.cmi \
driver/compenv.cmi \
utils/clflags.cmi \
toplevel/byte/topmain.cmi
toplevel/byte/topmain.cmx : \
- toplevel/byte/toploop.cmx \
- toplevel/byte/topdirs.cmx \
+ toplevel/byte/trace.cmx \
+ toplevel/toploop.cmx \
+ toplevel/byte/topeval.cmx \
+ toplevel/topdirs.cmx \
+ toplevel/topcommon.cmx \
+ typing/printtyp.cmx \
+ typing/path.cmx \
utils/misc.cmx \
driver/main_args.cmx \
parsing/location.cmx \
+ typing/env.cmx \
+ typing/ctype.cmx \
driver/compmisc.cmx \
driver/compenv.cmx \
utils/clflags.cmx \
@@ -6319,7 +6400,8 @@ toplevel/byte/topmain.cmx : \
toplevel/byte/topmain.cmi :
toplevel/byte/trace.cmo : \
typing/types.cmi \
- toplevel/byte/toploop.cmi \
+ toplevel/byte/topeval.cmi \
+ toplevel/topcommon.cmi \
typing/printtyp.cmi \
typing/predef.cmi \
typing/path.cmi \
@@ -6331,7 +6413,8 @@ toplevel/byte/trace.cmo : \
toplevel/byte/trace.cmi
toplevel/byte/trace.cmx : \
typing/types.cmx \
- toplevel/byte/toploop.cmx \
+ toplevel/byte/topeval.cmx \
+ toplevel/topcommon.cmx \
typing/printtyp.cmx \
typing/predef.cmx \
typing/path.cmx \
@@ -6346,66 +6429,26 @@ toplevel/byte/trace.cmi : \
typing/path.cmi \
parsing/longident.cmi \
typing/env.cmi
-toplevel/native/topdirs.cmo : \
- utils/warnings.cmi \
- typing/types.cmi \
- toplevel/native/toploop.cmi \
- typing/printtyp.cmi \
- utils/misc.cmi \
- parsing/longident.cmi \
- utils/load_path.cmi \
- typing/ident.cmi \
- typing/env.cmi \
- typing/ctype.cmi \
- utils/config.cmi \
- driver/compenv.cmi \
- utils/clflags.cmi \
- asmcomp/asmlink.cmi \
- toplevel/native/topdirs.cmi
-toplevel/native/topdirs.cmx : \
- utils/warnings.cmx \
- typing/types.cmx \
- toplevel/native/toploop.cmx \
- typing/printtyp.cmx \
- utils/misc.cmx \
- parsing/longident.cmx \
- utils/load_path.cmx \
- typing/ident.cmx \
- typing/env.cmx \
- typing/ctype.cmx \
- utils/config.cmx \
- driver/compenv.cmx \
- utils/clflags.cmx \
- asmcomp/asmlink.cmx \
- toplevel/native/topdirs.cmi
-toplevel/native/topdirs.cmi : \
- parsing/longident.cmi
-toplevel/native/toploop.cmo : \
+toplevel/native/topeval.cmo : \
utils/warnings.cmi \
typing/types.cmi \
typing/typemod.cmi \
typing/typedtree.cmi \
typing/typecore.cmi \
lambda/translmod.cmi \
+ toplevel/topcommon.cmi \
lambda/simplif.cmi \
asmcomp/proc.cmi \
typing/printtyped.cmi \
typing/printtyp.cmi \
lambda/printlambda.cmi \
- parsing/printast.cmi \
typing/predef.cmi \
- parsing/pprintast.cmi \
- driver/pparse.cmi \
typing/path.cmi \
parsing/parsetree.cmi \
- parsing/parse.cmi \
typing/outcometree.cmi \
- typing/oprint.cmi \
utils/misc.cmi \
- parsing/longident.cmi \
parsing/location.cmi \
utils/load_path.cmi \
- parsing/lexer.cmi \
lambda/lambda.cmi \
typing/includemod.cmi \
middle_end/flambda/import_approx.cmi \
@@ -6416,43 +6459,35 @@ toplevel/native/toploop.cmo : \
utils/config.cmi \
driver/compmisc.cmi \
middle_end/compilenv.cmi \
- driver/compenv.cmi \
middle_end/closure/closure_middle_end.cmi \
utils/clflags.cmi \
- typing/btype.cmi \
middle_end/backend_intf.cmi \
parsing/asttypes.cmi \
parsing/ast_helper.cmi \
asmcomp/asmlink.cmi \
asmcomp/asmgen.cmi \
asmcomp/arch.cmo \
- toplevel/native/toploop.cmi
-toplevel/native/toploop.cmx : \
+ toplevel/native/topeval.cmi
+toplevel/native/topeval.cmx : \
utils/warnings.cmx \
typing/types.cmx \
typing/typemod.cmx \
typing/typedtree.cmx \
typing/typecore.cmx \
lambda/translmod.cmx \
+ toplevel/topcommon.cmx \
lambda/simplif.cmx \
asmcomp/proc.cmx \
typing/printtyped.cmx \
typing/printtyp.cmx \
lambda/printlambda.cmx \
- parsing/printast.cmx \
typing/predef.cmx \
- parsing/pprintast.cmx \
- driver/pparse.cmx \
typing/path.cmx \
parsing/parsetree.cmi \
- parsing/parse.cmx \
typing/outcometree.cmi \
- typing/oprint.cmx \
utils/misc.cmx \
- parsing/longident.cmx \
parsing/location.cmx \
utils/load_path.cmx \
- parsing/lexer.cmx \
lambda/lambda.cmx \
typing/includemod.cmx \
middle_end/flambda/import_approx.cmx \
@@ -6463,29 +6498,24 @@ toplevel/native/toploop.cmx : \
utils/config.cmx \
driver/compmisc.cmx \
middle_end/compilenv.cmx \
- driver/compenv.cmx \
middle_end/closure/closure_middle_end.cmx \
utils/clflags.cmx \
- typing/btype.cmx \
middle_end/backend_intf.cmi \
parsing/asttypes.cmi \
parsing/ast_helper.cmx \
asmcomp/asmlink.cmx \
asmcomp/asmgen.cmx \
asmcomp/arch.cmx \
- toplevel/native/toploop.cmi
-toplevel/native/toploop.cmi : \
- utils/warnings.cmi \
- typing/types.cmi \
+ toplevel/native/topeval.cmi
+toplevel/native/topeval.cmi : \
+ toplevel/topcommon.cmi \
typing/path.cmi \
parsing/parsetree.cmi \
- typing/outcometree.cmi \
- parsing/longident.cmi \
- parsing/location.cmi \
typing/env.cmi
toplevel/native/topmain.cmo : \
- toplevel/native/toploop.cmi \
- toplevel/native/topdirs.cmi \
+ toplevel/toploop.cmi \
+ toplevel/native/topeval.cmi \
+ toplevel/topcommon.cmi \
utils/misc.cmi \
driver/main_args.cmi \
parsing/location.cmi \
@@ -6494,8 +6524,9 @@ toplevel/native/topmain.cmo : \
utils/clflags.cmi \
toplevel/native/topmain.cmi
toplevel/native/topmain.cmx : \
- toplevel/native/toploop.cmx \
- toplevel/native/topdirs.cmx \
+ toplevel/toploop.cmx \
+ toplevel/native/topeval.cmx \
+ toplevel/topcommon.cmx \
utils/misc.cmx \
driver/main_args.cmx \
parsing/location.cmx \
diff --git a/.gitignore b/.gitignore
index d88ffd6767..89b6ba95bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -263,13 +263,11 @@ _build
/tools/caml-tex
/tools/eventlog_metadata
-/toplevel/byte/toploop.mli
+/toplevel/byte/topeval.mli
/toplevel/byte/trace.mli
-/toplevel/byte/topdirs.mli
/toplevel/byte/topmain.mli
-/toplevel/native/toploop.mli
+/toplevel/native/topeval.mli
/toplevel/native/trace.mli
-/toplevel/native/topdirs.mli
/toplevel/native/topmain.mli
/utils/config.ml
diff --git a/Changes b/Changes
index 3e3ca01bc5..46edcc4c21 100644
--- a/Changes
+++ b/Changes
@@ -101,6 +101,10 @@ Working version
`Opttoploop`, `Opttopstart`, which are replaced by `Toploop` and `Topstart` in
library `ocamltoplevel`, made available in native code.
+- #10124: remove duplicated code from the native toplevel, split toplevel
+ implementation into the shared part (`Topcommon`, etc.) and specific ones
+ (`Topeval`, `Trace`, `Topmain`).
+
* #10086: add the commands `make list-parse-errors` and `make
generate-parse-errors` to generate a set of syntactically incorrect
sentences that covers all error states of the LR automaton. Add these
diff --git a/Makefile b/Makefile
index e3b3d83e6e..755c8189b9 100644
--- a/Makefile
+++ b/Makefile
@@ -67,6 +67,8 @@ OPTSTART=driver/optmain.cmo
TOPLEVELSTART=toplevel/topstart.cmo
+TOPLEVELINIT=toplevel/toploop.cmo
+
PERVASIVES=$(STDLIB_MODULES) outcometree topdirs toploop
LIBFILES=stdlib.cma std_exit.cmo *.cmi camlheader
@@ -400,8 +402,8 @@ endif
"$(INSTALL_LIBDIR)"
ifeq "$(INSTALL_SOURCE_ARTIFACTS)" "true"
$(INSTALL_DATA) \
- toplevel/byte/topdirs.cmt \
- toplevel/topdirs.cmti toplevel/byte/topdirs.mli \
+ toplevel/topdirs.cmt \
+ toplevel/topdirs.cmti toplevel/topdirs.mli \
"$(INSTALL_LIBDIR)"
endif
$(MAKE) -C tools install
@@ -544,7 +546,9 @@ installoptopt:
if test -f ocamlnat$(EXE) ; then \
$(INSTALL_PROG) ocamlnat$(EXE) "$(INSTALL_BINDIR)"; \
$(INSTALL_DATA) \
- $(TOPLEVELSTART:.cmo=.cmx) $(TOPLEVELSTART:.cmo=.$(O)) \
+ toplevel/*.cmx \
+ toplevel/native/*.cmx \
+ $(TOPLEVELSTART:.cmo=.$(O)) \
"$(INSTALL_COMPLIBDIR)"; \
fi
cd "$(INSTALL_COMPLIBDIR)" && \
@@ -1015,6 +1019,14 @@ ocamlnat$(EXE): compilerlibs/ocamlcommon.cmxa compilerlibs/ocamloptcomp.cmxa \
$(TOPLEVELSTART:.cmo=.cmx)
$(CAMLOPT_CMD) $(LINKFLAGS) -linkall -I toplevel/native -o $@ $^
+
+toplevel/topdirs.cmx: toplevel/topdirs.ml
+ $(CAMLOPT_CMD) $(COMPFLAGS) $(OPTCOMPFLAGS) -I toplevel/native -c $<
+
+$(TOPLEVELINIT:.cmo=.cmx): $(TOPLEVELINIT:.cmo=.ml) \
+ toplevel/native/topeval.cmx
+ $(CAMLOPT_CMD) $(COMPFLAGS) $(OPTCOMPFLAGS) -I toplevel/native -c $<
+
$(TOPLEVELSTART:.cmo=.cmx): $(TOPLEVELSTART:.cmo=.ml) \
toplevel/native/topmain.cmx
$(CAMLOPT_CMD) $(COMPFLAGS) $(OPTCOMPFLAGS) -I toplevel/native -c $<
@@ -1022,7 +1034,7 @@ $(TOPLEVELSTART:.cmo=.cmx): $(TOPLEVELSTART:.cmo=.ml) \
partialclean::
rm -f ocamlnat ocamlnat.exe
-toplevel/native/toploop.cmx: otherlibs/dynlink/dynlink.cmxa
+toplevel/native/topeval.cmx: otherlibs/dynlink/dynlink.cmxa
# The numeric opcodes
diff --git a/compilerlibs/Makefile.compilerlibs b/compilerlibs/Makefile.compilerlibs
index 9389e27396..f632d1cd76 100644
--- a/compilerlibs/Makefile.compilerlibs
+++ b/compilerlibs/Makefile.compilerlibs
@@ -261,17 +261,21 @@ MIDDLE_END_CMI=\
OPTCOMP=$(MIDDLE_END) $(ASMCOMP)
OPTCOMP_CMI=$(MIDDLE_END_CMI) $(ASMCOMP_CMI)
-TOPLEVEL=toplevel/genprintval.cmo toplevel/byte/toploop.cmo \
- toplevel/byte/trace.cmo toplevel/byte/topdirs.cmo toplevel/byte/topmain.cmo
-TOPLEVEL_CMI=toplevel/byte/toploop.cmi toplevel/byte/trace.cmi \
- toplevel/byte/topdirs.cmi toplevel/byte/topmain.cmi
-
-OPTTOPLEVEL=toplevel/genprintval.cmo toplevel/native/toploop.cmo \
- toplevel/native/topdirs.cmo toplevel/native/topmain.cmo
-OPTTOPLEVEL_CMI=toplevel/native/toploop.cmi toplevel/native/topdirs.cmi \
+TOPLEVEL=toplevel/genprintval.cmo toplevel/topcommon.cmo \
+ toplevel/byte/topeval.cmo toplevel/byte/trace.cmo toplevel/toploop.cmo \
+ toplevel/topdirs.cmo toplevel/byte/topmain.cmo
+TOPLEVEL_CMI=toplevel/topcommon.cmi toplevel/byte/topeval.cmi \
+ toplevel/byte/trace.cmi toplevel/toploop.cmi toplevel/topdirs.cmi \
+ toplevel/byte/topmain.cmi
+
+OPTTOPLEVEL=toplevel/genprintval.cmo toplevel/topcommon.cmo \
+ toplevel/native/topeval.cmo toplevel/native/trace.cmo toplevel/toploop.cmo \
+ toplevel/topdirs.cmo toplevel/native/topmain.cmo
+OPTTOPLEVEL_CMI=toplevel/topcommon.cmi toplevel/native/topeval.cmi \
+ toplevel/native/trace.cmi toplevel/toploop.cmi toplevel/topdirs.cmi \
toplevel/native/topmain.cmi
-TOPLEVEL_SHARED_MLIS = toploop.mli trace.mli topdirs.mli topmain.mli
+TOPLEVEL_SHARED_MLIS = topeval.mli trace.mli topmain.mli
toplevel/byte/%.mli toplevel/byte/%.cmi: toplevel/%.mli toplevel/%.cmi
cp toplevel/$*.mli toplevel/$*.cmi $(@D)
diff --git a/testsuite/tests/tool-toplevel/pr6468.compilers.reference b/testsuite/tests/tool-toplevel/pr6468.compilers.reference
index 90aa2e6bb6..bcb98ee2d4 100644
--- a/testsuite/tests/tool-toplevel/pr6468.compilers.reference
+++ b/testsuite/tests/tool-toplevel/pr6468.compilers.reference
@@ -10,5 +10,5 @@ Raised at f in file "//toplevel//", line 2, characters 11-26
Called from g in file "//toplevel//", line 1, characters 11-15
Called from Stdlib__fun.protect in file "fun.ml", line 33, characters 8-15
Re-raised at Stdlib__fun.protect in file "fun.ml", line 38, characters 6-52
-Called from Toploop.load_lambda in file "toplevel/byte/toploop.ml", line 212, characters 4-150
+Called from Topeval.load_lambda in file "toplevel/byte/topeval.ml", line 112, characters 4-150
diff --git a/tools/.depend b/tools/.depend
index 7fd73c053c..2158c038f3 100644
--- a/tools/.depend
+++ b/tools/.depend
@@ -12,7 +12,7 @@ caml_tex.cmo : \
../parsing/ast_iterator.cmi \
../parsing/ast_helper.cmi
caml_tex.cmx : \
- ../toplevel/toploop.cmi \
+ ../toplevel/toploop.cmx \
../parsing/syntaxerr.cmx \
../parsing/parsetree.cmi \
../parsing/parse.cmx \
diff --git a/toplevel/byte/topeval.ml b/toplevel/byte/topeval.ml
new file mode 100644
index 0000000000..eac9d2c4ad
--- /dev/null
+++ b/toplevel/byte/topeval.ml
@@ -0,0 +1,356 @@
+(**************************************************************************)
+(* *)
+(* OCaml *)
+(* *)
+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
+(* *)
+(* Copyright 1996 Institut National de Recherche en Informatique et *)
+(* en Automatique. *)
+(* *)
+(* All rights reserved. This file is distributed under the terms of *)
+(* the GNU Lesser General Public License version 2.1, with the *)
+(* special exception on linking described in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(* The interactive toplevel loop *)
+
+open Format
+open Misc
+open Parsetree
+open Types
+open Typedtree
+open Outcometree
+open Topcommon
+module String = Misc.Stdlib.String
+
+(* The table of toplevel value bindings and its accessors *)
+
+let toplevel_value_bindings : Obj.t String.Map.t ref = ref String.Map.empty
+
+let getvalue name =
+ try
+ String.Map.find name !toplevel_value_bindings
+ with Not_found ->
+ fatal_error (name ^ " unbound at toplevel")
+
+let setvalue name v =
+ toplevel_value_bindings := String.Map.add name v !toplevel_value_bindings
+
+(* Return the value referred to by a path *)
+
+let rec eval_address = function
+ | Env.Aident id ->
+ if Ident.persistent id || Ident.global id then
+ Symtable.get_global_value id
+ else begin
+ let name = Translmod.toplevel_name id in
+ try
+ String.Map.find name !toplevel_value_bindings
+ with Not_found ->
+ raise (Symtable.Error(Symtable.Undefined_global name))
+ end
+ | Env.Adot(p, pos) ->
+ Obj.field (eval_address p) pos
+
+let eval_path find env path =
+ match find path env with
+ | addr -> eval_address addr
+ | exception Not_found ->
+ fatal_error ("Cannot find address for: " ^ (Path.name path))
+
+let eval_module_path env path =
+ eval_path Env.find_module_address env path
+
+let eval_value_path env path =
+ eval_path Env.find_value_address env path
+
+let eval_extension_path env path =
+ eval_path Env.find_constructor_address env path
+
+let eval_class_path env path =
+ eval_path Env.find_class_address env path
+
+(* To print values *)
+
+module EvalPath = struct
+ type valu = Obj.t
+ exception Error
+ let eval_address addr =
+ try eval_address addr with Symtable.Error _ -> raise Error
+ let same_value v1 v2 = (v1 == v2)
+end
+
+include Topcommon.MakePrinter(Obj)(Genprintval.Make(Obj)(EvalPath))
+
+
+(* Load in-core and execute a lambda term *)
+
+let may_trace = ref false (* Global lock on tracing *)
+
+let load_lambda ppf lam =
+ if !Clflags.dump_rawlambda then fprintf ppf "%a@." Printlambda.lambda lam;
+ let slam = Simplif.simplify_lambda lam in
+ if !Clflags.dump_lambda then fprintf ppf "%a@." Printlambda.lambda slam;
+ let (init_code, fun_code) = Bytegen.compile_phrase slam in
+ if !Clflags.dump_instr then
+ fprintf ppf "%a%a@."
+ Printinstr.instrlist init_code
+ Printinstr.instrlist fun_code;
+ let (code, reloc, events) =
+ Emitcode.to_memory init_code fun_code
+ in
+ let can_free = (fun_code = []) in
+ let initial_symtable = Symtable.current_state() in
+ Symtable.patch_object code reloc;
+ Symtable.check_global_initialized reloc;
+ Symtable.update_global_table();
+ let initial_bindings = !toplevel_value_bindings in
+ let bytecode, closure = Meta.reify_bytecode code [| events |] None in
+ match
+ may_trace := true;
+ Fun.protect
+ ~finally:(fun () -> may_trace := false;
+ if can_free then Meta.release_bytecode bytecode)
+ closure
+ with
+ | retval -> Result retval
+ | exception x ->
+ record_backtrace ();
+ toplevel_value_bindings := initial_bindings; (* PR#6211 *)
+ Symtable.restore_state initial_symtable;
+ Exception x
+
+(* Print the outcome of an evaluation *)
+
+let pr_item =
+ Printtyp.print_items
+ (fun env -> function
+ | Sig_value(id, {val_kind = Val_reg; val_type}, _) ->
+ Some (outval_of_value env (getvalue (Translmod.toplevel_name id))
+ val_type)
+ | _ -> None
+ )
+
+(* Execute a toplevel phrase *)
+
+let execute_phrase print_outcome ppf phr =
+ match phr with
+ | Ptop_def sstr ->
+ let oldenv = !toplevel_env in
+ Typecore.reset_delayed_checks ();
+ let (str, sg, sn, newenv) = Typemod.type_toplevel_phrase oldenv sstr in
+ if !Clflags.dump_typedtree then Printtyped.implementation ppf str;
+ let sg' = Typemod.Signature_names.simplify newenv sn sg in
+ ignore (Includemod.signatures ~mark:Mark_positive oldenv sg sg');
+ Typecore.force_delayed_checks ();
+ let lam = Translmod.transl_toplevel_definition str in
+ Warnings.check_fatal ();
+ begin try
+ toplevel_env := newenv;
+ let res = load_lambda ppf lam in
+ let out_phr =
+ match res with
+ | Result v ->
+ if print_outcome then
+ Printtyp.wrap_printing_env ~error:false oldenv (fun () ->
+ match str.str_items with
+ | [ { str_desc =
+ (Tstr_eval (exp, _)
+ |Tstr_value
+ (Asttypes.Nonrecursive,
+ [{vb_pat = {pat_desc=Tpat_any};
+ vb_expr = exp}
+ ]
+ )
+ )
+ }
+ ] ->
+ let outv = outval_of_value newenv v exp.exp_type in
+ let ty = Printtyp.tree_of_type_scheme exp.exp_type in
+ Ophr_eval (outv, ty)
+
+ | [] -> Ophr_signature []
+ | _ -> Ophr_signature (pr_item oldenv sg'))
+ else Ophr_signature []
+ | Exception exn ->
+ toplevel_env := oldenv;
+ if exn = Out_of_memory then Gc.full_major();
+ let outv =
+ outval_of_value !toplevel_env (Obj.repr exn) Predef.type_exn
+ in
+ Ophr_exception (exn, outv)
+ in
+ !print_out_phrase ppf out_phr;
+ if Printexc.backtrace_status ()
+ then begin
+ match !backtrace with
+ | None -> ()
+ | Some b ->
+ pp_print_string ppf b;
+ pp_print_flush ppf ();
+ backtrace := None;
+ end;
+ begin match out_phr with
+ | Ophr_eval (_, _) | Ophr_signature _ -> true
+ | Ophr_exception _ -> false
+ end
+ with x ->
+ toplevel_env := oldenv; raise x
+ end
+ | Ptop_dir {pdir_name = {Location.txt = dir_name}; pdir_arg } ->
+ begin match Topcommon.get_directive dir_name with
+ | None ->
+ fprintf ppf "Unknown directive `%s'." dir_name;
+ let directives = Topcommon.all_directive_names () in
+ Misc.did_you_mean ppf
+ (fun () -> Misc.spellcheck directives dir_name);
+ fprintf ppf "@.";
+ false
+ | Some d ->
+ match d, pdir_arg with
+ | Directive_none f, None -> f (); true
+ | Directive_string f, Some {pdira_desc = Pdir_string s} -> f s; true
+ | Directive_int f, Some {pdira_desc = Pdir_int (n,None) } ->
+ begin match Int_literal_converter.int n with
+ | n -> f n; true
+ | exception _ ->
+ fprintf ppf "Integer literal exceeds the range of \
+ representable integers for directive `%s'.@."
+ dir_name;
+ false
+ end
+ | Directive_int _, Some {pdira_desc = Pdir_int (_, Some _)} ->
+ fprintf ppf "Wrong integer literal for directive `%s'.@."
+ dir_name;
+ false
+ | Directive_ident f, Some {pdira_desc = Pdir_ident lid} -> f lid; true
+ | Directive_bool f, Some {pdira_desc = Pdir_bool b} -> f b; true
+ | _ ->
+ fprintf ppf "Wrong type of argument for directive `%s'.@."
+ dir_name;
+ false
+ end
+
+let execute_phrase print_outcome ppf phr =
+ try execute_phrase print_outcome ppf phr
+ with exn ->
+ Warnings.reset_fatal ();
+ raise exn
+
+
+(* Additional directives for the bytecode toplevel only *)
+
+open Cmo_format
+
+(* Loading files *)
+
+exception Load_failed
+
+let check_consistency ppf filename cu =
+ try Env.import_crcs ~source:filename cu.cu_imports
+ with Persistent_env.Consistbl.Inconsistency {
+ unit_name = name;
+ inconsistent_source = user;
+ original_source = auth;
+ } ->
+ fprintf ppf "@[<hv 0>The files %s@ and %s@ \
+ disagree over interface %s@]@."
+ user auth name;
+ raise Load_failed
+
+(* This is basically Dynlink.Bytecode.run with no digest *)
+let load_compunit ic filename ppf compunit =
+ check_consistency ppf filename compunit;
+ seek_in ic compunit.cu_pos;
+ let code_size = compunit.cu_codesize + 8 in
+ let code = LongString.create code_size in
+ LongString.input_bytes_into code ic compunit.cu_codesize;
+ LongString.set code compunit.cu_codesize (Char.chr Opcodes.opRETURN);
+ LongString.blit_string "\000\000\000\001\000\000\000" 0
+ code (compunit.cu_codesize + 1) 7;
+ let initial_symtable = Symtable.current_state() in
+ Symtable.patch_object code compunit.cu_reloc;
+ Symtable.update_global_table();
+ let events =
+ if compunit.cu_debug = 0 then [| |]
+ else begin
+ seek_in ic compunit.cu_debug;
+ [| input_value ic |]
+ end in
+ begin try
+ may_trace := true;
+ let _bytecode, closure = Meta.reify_bytecode code events None in
+ ignore (closure ());
+ may_trace := false;
+ with exn ->
+ record_backtrace ();
+ may_trace := false;
+ Symtable.restore_state initial_symtable;
+ print_exception_outcome ppf exn;
+ raise Load_failed
+ end
+
+let rec load_file recursive ppf name =
+ let filename =
+ try Some (Load_path.find name) with Not_found -> None
+ in
+ match filename with
+ | None -> fprintf ppf "Cannot find file %s.@." name; false
+ | Some filename ->
+ let ic = open_in_bin filename in
+ Misc.try_finally
+ ~always:(fun () -> close_in ic)
+ (fun () -> really_load_file recursive ppf name filename ic)
+
+and really_load_file recursive ppf name filename ic =
+ let buffer = really_input_string ic (String.length Config.cmo_magic_number) in
+ try
+ if buffer = Config.cmo_magic_number then begin
+ let compunit_pos = input_binary_int ic in (* Go to descriptor *)
+ seek_in ic compunit_pos;
+ let cu : compilation_unit = input_value ic in
+ if recursive then
+ List.iter
+ (function
+ | (Reloc_getglobal id, _)
+ when not (Symtable.is_global_defined id) ->
+ let file = Ident.name id ^ ".cmo" in
+ begin match Load_path.find_uncap file with
+ | exception Not_found -> ()
+ | file ->
+ if not (load_file recursive ppf file) then raise Load_failed
+ end
+ | _ -> ()
+ )
+ cu.cu_reloc;
+ load_compunit ic filename ppf cu;
+ true
+ end else
+ if buffer = Config.cma_magic_number then begin
+ let toc_pos = input_binary_int ic in (* Go to table of contents *)
+ seek_in ic toc_pos;
+ let lib = (input_value ic : library) in
+ List.iter
+ (fun dllib ->
+ let name = Dll.extract_dll_name dllib in
+ try Dll.open_dlls Dll.For_execution [name]
+ with Failure reason ->
+ fprintf ppf
+ "Cannot load required shared library %s.@.Reason: %s.@."
+ name reason;
+ raise Load_failed)
+ lib.lib_dllibs;
+ List.iter (load_compunit ic filename ppf) lib.lib_units;
+ true
+ end else begin
+ fprintf ppf "File %s is not a bytecode object file.@." name;
+ false
+ end
+ with Load_failed -> false
+
+let init () =
+ let crc_intfs = Symtable.init_toplevel() in
+ Compmisc.init_path ();
+ Env.import_crcs ~source:Sys.executable_name crc_intfs;
+ ()
diff --git a/toplevel/byte/toploop.ml b/toplevel/byte/toploop.ml
deleted file mode 100644
index 6f0c12b556..0000000000
--- a/toplevel/byte/toploop.ml
+++ /dev/null
@@ -1,649 +0,0 @@
-(**************************************************************************)
-(* *)
-(* OCaml *)
-(* *)
-(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
-(* *)
-(* Copyright 1996 Institut National de Recherche en Informatique et *)
-(* en Automatique. *)
-(* *)
-(* All rights reserved. This file is distributed under the terms of *)
-(* the GNU Lesser General Public License version 2.1, with the *)
-(* special exception on linking described in the file LICENSE. *)
-(* *)
-(**************************************************************************)
-
-(* The interactive toplevel loop *)
-
-open Format
-open Misc
-open Parsetree
-open Types
-open Typedtree
-open Outcometree
-open Ast_helper
-module String = Misc.Stdlib.String
-
-type directive_fun =
- | Directive_none of (unit -> unit)
- | Directive_string of (string -> unit)
- | Directive_int of (int -> unit)
- | Directive_ident of (Longident.t -> unit)
- | Directive_bool of (bool -> unit)
-
-type directive_info = {
- section: string;
- doc: string;
-}
-
-(* Phase buffer that stores the last toplevel phrase (see
- [Location.input_phrase_buffer]). *)
-let phrase_buffer = Buffer.create 1024
-
-(* The table of toplevel value bindings and its accessors *)
-
-let toplevel_value_bindings : Obj.t String.Map.t ref = ref String.Map.empty
-
-let getvalue name =
- try
- String.Map.find name !toplevel_value_bindings
- with Not_found ->
- fatal_error (name ^ " unbound at toplevel")
-
-let setvalue name v =
- toplevel_value_bindings := String.Map.add name v !toplevel_value_bindings
-
-(* Return the value referred to by a path *)
-
-let rec eval_address = function
- | Env.Aident id ->
- if Ident.persistent id || Ident.global id then
- Symtable.get_global_value id
- else begin
- let name = Translmod.toplevel_name id in
- try
- String.Map.find name !toplevel_value_bindings
- with Not_found ->
- raise (Symtable.Error(Symtable.Undefined_global name))
- end
- | Env.Adot(p, pos) ->
- Obj.field (eval_address p) pos
-
-let eval_path find env path =
- match find path env with
- | addr -> eval_address addr
- | exception Not_found ->
- fatal_error ("Cannot find address for: " ^ (Path.name path))
-
-let eval_module_path env path =
- eval_path Env.find_module_address env path
-
-let eval_value_path env path =
- eval_path Env.find_value_address env path
-
-let eval_extension_path env path =
- eval_path Env.find_constructor_address env path
-
-let eval_class_path env path =
- eval_path Env.find_class_address env path
-
-(* To print values *)
-
-module EvalPath = struct
- type valu = Obj.t
- exception Error
- let eval_address addr =
- try eval_address addr with Symtable.Error _ -> raise Error
- let same_value v1 v2 = (v1 == v2)
-end
-
-module Printer = Genprintval.Make(Obj)(EvalPath)
-
-let max_printer_depth = ref 100
-let max_printer_steps = ref 300
-
-let print_out_value = Oprint.out_value
-let print_out_type = Oprint.out_type
-let print_out_class_type = Oprint.out_class_type
-let print_out_module_type = Oprint.out_module_type
-let print_out_type_extension = Oprint.out_type_extension
-let print_out_sig_item = Oprint.out_sig_item
-let print_out_signature = Oprint.out_signature
-let print_out_phrase = Oprint.out_phrase
-
-let print_untyped_exception ppf obj =
- !print_out_value ppf (Printer.outval_of_untyped_exception obj)
-let outval_of_value env obj ty =
- Printer.outval_of_value !max_printer_steps !max_printer_depth
- (fun _ _ _ -> None) env obj ty
-let print_value env obj ppf ty =
- !print_out_value ppf (outval_of_value env obj ty)
-
-type ('a, 'b) gen_printer = ('a, 'b) Genprintval.gen_printer =
- | Zero of 'b
- | Succ of ('a -> ('a, 'b) gen_printer)
-
-let install_printer = Printer.install_printer
-let install_generic_printer = Printer.install_generic_printer
-let install_generic_printer' = Printer.install_generic_printer'
-let remove_printer = Printer.remove_printer
-
-(* Hooks for parsing functions *)
-
-let parse_toplevel_phrase = ref Parse.toplevel_phrase
-let parse_use_file = ref Parse.use_file
-let print_location = Location.print_loc
-let print_error = Location.print_report
-let print_warning = Location.print_warning
-let input_name = Location.input_name
-
-let parse_mod_use_file name lb =
- let modname =
- String.capitalize_ascii
- (Filename.remove_extension (Filename.basename name))
- in
- let items =
- List.concat
- (List.map
- (function Ptop_def s -> s | Ptop_dir _ -> [])
- (!parse_use_file lb))
- in
- [ Ptop_def
- [ Str.module_
- (Mb.mk
- (Location.mknoloc (Some modname))
- (Mod.structure items)
- )
- ]
- ]
-
-(* Hook for initialization *)
-
-let toplevel_startup_hook = ref (fun () -> ())
-
-type event = ..
-type event +=
- | Startup
- | After_setup
-
-let hooks = ref []
-
-let add_hook f = hooks := f :: !hooks
-
-let () =
- add_hook (function
- | Startup -> !toplevel_startup_hook ()
- | _ -> ())
-
-let run_hooks hook = List.iter (fun f -> f hook) !hooks
-
-(* Load in-core and execute a lambda term *)
-
-let may_trace = ref false (* Global lock on tracing *)
-type evaluation_outcome = Result of Obj.t | Exception of exn
-
-let backtrace = ref None
-
-let record_backtrace () =
- if Printexc.backtrace_status ()
- then backtrace := Some (Printexc.get_backtrace ())
-
-let load_lambda ppf lam =
- if !Clflags.dump_rawlambda then fprintf ppf "%a@." Printlambda.lambda lam;
- let slam = Simplif.simplify_lambda lam in
- if !Clflags.dump_lambda then fprintf ppf "%a@." Printlambda.lambda slam;
- let (init_code, fun_code) = Bytegen.compile_phrase slam in
- if !Clflags.dump_instr then
- fprintf ppf "%a%a@."
- Printinstr.instrlist init_code
- Printinstr.instrlist fun_code;
- let (code, reloc, events) =
- Emitcode.to_memory init_code fun_code
- in
- let can_free = (fun_code = []) in
- let initial_symtable = Symtable.current_state() in
- Symtable.patch_object code reloc;
- Symtable.check_global_initialized reloc;
- Symtable.update_global_table();
- let initial_bindings = !toplevel_value_bindings in
- let bytecode, closure = Meta.reify_bytecode code [| events |] None in
- match
- may_trace := true;
- Fun.protect
- ~finally:(fun () -> may_trace := false;
- if can_free then Meta.release_bytecode bytecode)
- closure
- with
- | retval -> Result retval
- | exception x ->
- record_backtrace ();
- toplevel_value_bindings := initial_bindings; (* PR#6211 *)
- Symtable.restore_state initial_symtable;
- Exception x
-
-(* Print the outcome of an evaluation *)
-
-let pr_item =
- Printtyp.print_items
- (fun env -> function
- | Sig_value(id, {val_kind = Val_reg; val_type}, _) ->
- Some (outval_of_value env (getvalue (Translmod.toplevel_name id))
- val_type)
- | _ -> None
- )
-
-(* The current typing environment for the toplevel *)
-
-let toplevel_env = ref Env.empty
-
-(* Print an exception produced by an evaluation *)
-
-let print_out_exception ppf exn outv =
- !print_out_phrase ppf (Ophr_exception (exn, outv))
-
-let print_exception_outcome ppf exn =
- if exn = Out_of_memory then Gc.full_major ();
- let outv = outval_of_value !toplevel_env (Obj.repr exn) Predef.type_exn in
- print_out_exception ppf exn outv;
- if Printexc.backtrace_status ()
- then
- match !backtrace with
- | None -> ()
- | Some b ->
- print_string b;
- backtrace := None
-
-
-(* Inserting new toplevel directives *)
-
-let directive_table = (Hashtbl.create 23 : (string, directive_fun) Hashtbl.t)
-
-let directive_info_table =
- (Hashtbl.create 23 : (string, directive_info) Hashtbl.t)
-
-let add_directive name dir_fun dir_info =
- Hashtbl.add directive_table name dir_fun;
- Hashtbl.add directive_info_table name dir_info
-
-(* Execute a toplevel phrase *)
-
-let execute_phrase print_outcome ppf phr =
- match phr with
- | Ptop_def sstr ->
- let oldenv = !toplevel_env in
- Typecore.reset_delayed_checks ();
- let (str, sg, sn, newenv) = Typemod.type_toplevel_phrase oldenv sstr in
- if !Clflags.dump_typedtree then Printtyped.implementation ppf str;
- let sg' = Typemod.Signature_names.simplify newenv sn sg in
- ignore (Includemod.signatures ~mark:Mark_positive oldenv sg sg');
- Typecore.force_delayed_checks ();
- let lam = Translmod.transl_toplevel_definition str in
- Warnings.check_fatal ();
- begin try
- toplevel_env := newenv;
- let res = load_lambda ppf lam in
- let out_phr =
- match res with
- | Result v ->
- if print_outcome then
- Printtyp.wrap_printing_env ~error:false oldenv (fun () ->
- match str.str_items with
- | [ { str_desc =
- (Tstr_eval (exp, _)
- |Tstr_value
- (Asttypes.Nonrecursive,
- [{vb_pat = {pat_desc=Tpat_any};
- vb_expr = exp}
- ]
- )
- )
- }
- ] ->
- let outv = outval_of_value newenv v exp.exp_type in
- let ty = Printtyp.tree_of_type_scheme exp.exp_type in
- Ophr_eval (outv, ty)
-
- | [] -> Ophr_signature []
- | _ -> Ophr_signature (pr_item oldenv sg'))
- else Ophr_signature []
- | Exception exn ->
- toplevel_env := oldenv;
- if exn = Out_of_memory then Gc.full_major();
- let outv =
- outval_of_value !toplevel_env (Obj.repr exn) Predef.type_exn
- in
- Ophr_exception (exn, outv)
- in
- !print_out_phrase ppf out_phr;
- if Printexc.backtrace_status ()
- then begin
- match !backtrace with
- | None -> ()
- | Some b ->
- pp_print_string ppf b;
- pp_print_flush ppf ();
- backtrace := None;
- end;
- begin match out_phr with
- | Ophr_eval (_, _) | Ophr_signature _ -> true
- | Ophr_exception _ -> false
- end
- with x ->
- toplevel_env := oldenv; raise x
- end
- | Ptop_dir {pdir_name = {Location.txt = dir_name}; pdir_arg } ->
- let d =
- try Some (Hashtbl.find directive_table dir_name)
- with Not_found -> None
- in
- begin match d with
- | None ->
- fprintf ppf "Unknown directive `%s'." dir_name;
- let directives =
- Hashtbl.fold (fun dir _ acc -> dir::acc) directive_table [] in
- Misc.did_you_mean ppf
- (fun () -> Misc.spellcheck directives dir_name);
- fprintf ppf "@.";
- false
- | Some d ->
- match d, pdir_arg with
- | Directive_none f, None -> f (); true
- | Directive_string f, Some {pdira_desc = Pdir_string s} -> f s; true
- | Directive_int f, Some {pdira_desc = Pdir_int (n,None) } ->
- begin match Int_literal_converter.int n with
- | n -> f n; true
- | exception _ ->
- fprintf ppf "Integer literal exceeds the range of \
- representable integers for directive `%s'.@."
- dir_name;
- false
- end
- | Directive_int _, Some {pdira_desc = Pdir_int (_, Some _)} ->
- fprintf ppf "Wrong integer literal for directive `%s'.@."
- dir_name;
- false
- | Directive_ident f, Some {pdira_desc = Pdir_ident lid} -> f lid; true
- | Directive_bool f, Some {pdira_desc = Pdir_bool b} -> f b; true
- | _ ->
- fprintf ppf "Wrong type of argument for directive `%s'.@."
- dir_name;
- false
- end
-
-let execute_phrase print_outcome ppf phr =
- try execute_phrase print_outcome ppf phr
- with exn ->
- Warnings.reset_fatal ();
- raise exn
-
-(* Read and execute commands from a file, or from stdin if [name] is "". *)
-
-let use_print_results = ref true
-
-let preprocess_phrase ppf phr =
- let phr =
- match phr with
- | Ptop_def str ->
- let str =
- Pparse.apply_rewriters_str ~restore:true ~tool_name:"ocaml" str
- in
- Ptop_def str
- | phr -> phr
- in
- if !Clflags.dump_parsetree then Printast.top_phrase ppf phr;
- if !Clflags.dump_source then Pprintast.top_phrase ppf phr;
- phr
-
-let use_channel ppf ~wrap_in_module ic name filename =
- let lb = Lexing.from_channel ic in
- Warnings.reset_fatal ();
- Location.init lb filename;
- (* Skip initial #! line if any *)
- Lexer.skip_hash_bang lb;
- protect_refs [ R (Location.input_name, filename);
- R (Location.input_lexbuf, Some lb); ]
- (fun () ->
- try
- List.iter
- (fun ph ->
- let ph = preprocess_phrase ppf ph in
- if not (execute_phrase !use_print_results ppf ph) then raise Exit)
- (if wrap_in_module then
- parse_mod_use_file name lb
- else
- !parse_use_file lb);
- true
- with
- | Exit -> false
- | Sys.Break -> fprintf ppf "Interrupted.@."; false
- | x -> Location.report_exception ppf x; false)
-
-let use_output ppf command =
- let fn = Filename.temp_file "ocaml" "_toploop.ml" in
- Misc.try_finally ~always:(fun () ->
- try Sys.remove fn with Sys_error _ -> ())
- (fun () ->
- match
- Printf.ksprintf Sys.command "%s > %s"
- command
- (Filename.quote fn)
- with
- | 0 ->
- let ic = open_in_bin fn in
- Misc.try_finally ~always:(fun () -> close_in ic)
- (fun () ->
- use_channel ppf ~wrap_in_module:false ic "" "(command-output)")
- | n ->
- fprintf ppf "Command exited with code %d.@." n;
- false)
-
-let use_file ppf ~wrap_in_module name =
- match name with
- | "" ->
- use_channel ppf ~wrap_in_module stdin name "(stdin)"
- | _ ->
- match Load_path.find name with
- | filename ->
- let ic = open_in_bin filename in
- Misc.try_finally ~always:(fun () -> close_in ic)
- (fun () -> use_channel ppf ~wrap_in_module ic name filename)
- | exception Not_found ->
- fprintf ppf "Cannot find file %s.@." name;
- false
-
-let mod_use_file ppf name =
- use_file ppf ~wrap_in_module:true name
-let use_file ppf name =
- use_file ppf ~wrap_in_module:false name
-
-let use_silently ppf name =
- protect_refs [ R (use_print_results, false) ] (fun () -> use_file ppf name)
-
-(* Reading function for interactive use *)
-
-let first_line = ref true
-let got_eof = ref false;;
-
-let read_input_default prompt buffer len =
- output_string stdout prompt; flush stdout;
- let i = ref 0 in
- try
- while true do
- if !i >= len then raise Exit;
- let c = input_char stdin in
- Bytes.set buffer !i c;
- (* Also populate the phrase buffer as new characters are added. *)
- Buffer.add_char phrase_buffer c;
- incr i;
- if c = '\n' then raise Exit;
- done;
- (!i, false)
- with
- | End_of_file ->
- (!i, true)
- | Exit ->
- (!i, false)
-
-let read_interactive_input = ref read_input_default
-
-let refill_lexbuf buffer len =
- if !got_eof then (got_eof := false; 0) else begin
- let prompt =
- if !Clflags.noprompt then ""
- else if !first_line then "# "
- else if !Clflags.nopromptcont then ""
- else if Lexer.in_comment () then "* "
- else " "
- in
- first_line := false;
- let (len, eof) = !read_interactive_input prompt buffer len in
- if eof then begin
- Location.echo_eof ();
- if len > 0 then got_eof := true;
- len
- end else
- len
- end
-
-(* Toplevel initialization. Performed here instead of at the
- beginning of loop() so that user code linked in with ocamlmktop
- can call directives from Topdirs. *)
-
-let _ =
- if !Sys.interactive then (* PR#6108 *)
- invalid_arg "The ocamltoplevel.cma library from compiler-libs \
- cannot be loaded inside the OCaml toplevel";
- Sys.interactive := true;
- let crc_intfs = Symtable.init_toplevel() in
- Compmisc.init_path ();
- Env.import_crcs ~source:Sys.executable_name crc_intfs;
- ()
-
-let find_ocamlinit () =
- let ocamlinit = ".ocamlinit" in
- if Sys.file_exists ocamlinit then Some ocamlinit else
- let getenv var = match Sys.getenv var with
- | exception Not_found -> None | "" -> None | v -> Some v
- in
- let exists_in_dir dir file = match dir with
- | None -> None
- | Some dir ->
- let file = Filename.concat dir file in
- if Sys.file_exists file then Some file else None
- in
- let home_dir () = getenv "HOME" in
- let config_dir () =
- if Sys.win32 then None else
- match getenv "XDG_CONFIG_HOME" with
- | Some _ as v -> v
- | None ->
- match home_dir () with
- | None -> None
- | Some dir -> Some (Filename.concat dir ".config")
- in
- let init_ml = Filename.concat "ocaml" "init.ml" in
- match exists_in_dir (config_dir ()) init_ml with
- | Some _ as v -> v
- | None -> exists_in_dir (home_dir ()) ocamlinit
-
-let load_ocamlinit ppf =
- if !Clflags.noinit then ()
- else match !Clflags.init_file with
- | Some f -> if Sys.file_exists f then ignore (use_silently ppf f)
- else fprintf ppf "Init file not found: \"%s\".@." f
- | None ->
- match find_ocamlinit () with
- | None -> ()
- | Some file -> ignore (use_silently ppf file)
-;;
-
-let set_paths () =
- (* Add whatever -I options have been specified on the command line,
- but keep the directories that user code linked in with ocamlmktop
- may have added to load_path. *)
- let expand = Misc.expand_directory Config.standard_library in
- let current_load_path = Load_path.get_paths () in
- let load_path = List.concat [
- [ "" ];
- List.map expand (List.rev !Compenv.first_include_dirs);
- List.map expand (List.rev !Clflags.include_dirs);
- List.map expand (List.rev !Compenv.last_include_dirs);
- current_load_path;
- [expand "+camlp4"];
- ]
- in
- Load_path.init load_path;
- Dll.add_path load_path
-
-let initialize_toplevel_env () =
- toplevel_env := Compmisc.initial_env()
-
-(* The interactive loop *)
-
-exception PPerror
-
-let loop ppf =
- Clflags.debug := true;
- Location.formatter_for_warnings := ppf;
- if not !Clflags.noversion then
- fprintf ppf " OCaml version %s@.@." Config.version;
- begin
- try initialize_toplevel_env ()
- with Env.Error _ | Typetexp.Error _ as exn ->
- Location.report_exception ppf exn; raise (Compenv.Exit_with_status 2)
- end;
- let lb = Lexing.from_function refill_lexbuf in
- Location.init lb "//toplevel//";
- Location.input_name := "//toplevel//";
- Location.input_lexbuf := Some lb;
- Location.input_phrase_buffer := Some phrase_buffer;
- Sys.catch_break true;
- run_hooks After_setup;
- load_ocamlinit ppf;
- while true do
- let snap = Btype.snapshot () in
- try
- Lexing.flush_input lb;
- (* Reset the phrase buffer when we flush the lexing buffer. *)
- Buffer.reset phrase_buffer;
- Location.reset();
- Warnings.reset_fatal ();
- first_line := true;
- let phr = try !parse_toplevel_phrase lb with Exit -> raise PPerror in
- let phr = preprocess_phrase ppf phr in
- Env.reset_cache_toplevel ();
- ignore(execute_phrase true ppf phr)
- with
- | End_of_file -> raise (Compenv.Exit_with_status 0)
- | Sys.Break -> fprintf ppf "Interrupted.@."; Btype.backtrack snap
- | PPerror -> ()
- | x -> Location.report_exception ppf x; Btype.backtrack snap
- done
-
-external caml_sys_modify_argv : string array -> unit =
- "caml_sys_modify_argv"
-
-let override_sys_argv new_argv =
- caml_sys_modify_argv new_argv;
- Arg.current := 0
-
-(* Execute a script. If [name] is "", read the script from stdin. *)
-
-let run_script ppf name args =
- override_sys_argv args;
- Compmisc.init_path ~dir:(Filename.dirname name) ();
- (* Note: would use [Filename.abspath] here, if we had it. *)
- begin
- try toplevel_env := Compmisc.initial_env()
- with Env.Error _ | Typetexp.Error _ as exn ->
- Location.report_exception ppf exn; raise (Compenv.Exit_with_status 2)
- end;
- Sys.interactive := false;
- run_hooks After_setup;
- let explicit_name =
- (* Prevent use_silently from searching in the path. *)
- if name <> "" && Filename.is_implicit name
- then Filename.concat Filename.current_dir_name name
- else name
- in
- use_silently ppf explicit_name
diff --git a/toplevel/byte/topmain.ml b/toplevel/byte/topmain.ml
index a0020b680b..0fdc12136e 100644
--- a/toplevel/byte/topmain.ml
+++ b/toplevel/byte/topmain.ml
@@ -13,6 +13,112 @@
(* *)
(**************************************************************************)
+
+(* The trace *)
+
+open Trace
+
+external current_environment: unit -> Obj.t = "caml_get_current_environment"
+
+let tracing_function_ptr =
+ get_code_pointer
+ (Obj.repr (fun arg -> Trace.print_trace (current_environment()) arg))
+
+let dir_trace ppf lid =
+ match Env.find_value_by_name lid !Topcommon.toplevel_env with
+ | (path, desc) -> begin
+ (* Check if this is a primitive *)
+ match desc.val_kind with
+ | Val_prim _ ->
+ Format.fprintf ppf
+ "%a is an external function and cannot be traced.@."
+ Printtyp.longident lid
+ | _ ->
+ let clos = Toploop.eval_value_path !Topcommon.toplevel_env path in
+ (* Nothing to do if it's not a closure *)
+ if Obj.is_block clos
+ && (Obj.tag clos = Obj.closure_tag || Obj.tag clos = Obj.infix_tag)
+ && (match
+ Ctype.(repr (expand_head !Topcommon.toplevel_env desc.val_type))
+ with {desc=Tarrow _} -> true | _ -> false)
+ then begin
+ match is_traced clos with
+ | Some opath ->
+ Format.fprintf ppf "%a is already traced (under the name %a).@."
+ Printtyp.path path
+ Printtyp.path opath
+ | None ->
+ (* Instrument the old closure *)
+ traced_functions :=
+ { path = path;
+ closure = clos;
+ actual_code = get_code_pointer clos;
+ instrumented_fun =
+ instrument_closure
+ !Topcommon.toplevel_env lid ppf desc.val_type }
+ :: !traced_functions;
+ (* Redirect the code field of the closure to point
+ to the instrumentation function *)
+ set_code_pointer clos tracing_function_ptr;
+ Format.fprintf ppf "%a is now traced.@." Printtyp.longident lid
+ end else
+ Format.fprintf ppf "%a is not a function.@." Printtyp.longident lid
+ end
+ | exception Not_found ->
+ Format.fprintf ppf "Unbound value %a.@." Printtyp.longident lid
+
+let dir_untrace ppf lid =
+ match Env.find_value_by_name lid !Topcommon.toplevel_env with
+ | (path, _desc) ->
+ let rec remove = function
+ | [] ->
+ Format.fprintf ppf "%a was not traced.@." Printtyp.longident lid;
+ []
+ | f :: rem ->
+ if Path.same f.path path then begin
+ set_code_pointer f.closure f.actual_code;
+ Format.fprintf ppf "%a is no longer traced.@."
+ Printtyp.longident lid;
+ rem
+ end else f :: remove rem in
+ traced_functions := remove !traced_functions
+ | exception Not_found ->
+ Format.fprintf ppf "Unbound value %a.@." Printtyp.longident lid
+
+let dir_untrace_all ppf () =
+ List.iter
+ (fun f ->
+ set_code_pointer f.closure f.actual_code;
+ Format.fprintf ppf "%a is no longer traced.@." Printtyp.path f.path)
+ !traced_functions;
+ traced_functions := []
+
+let _ = Topcommon.add_directive "trace"
+ (Directive_ident (dir_trace Format.std_formatter))
+ {
+ section = Topdirs.section_trace;
+ doc = "All calls to the function \
+ named function-name will be traced.";
+ }
+
+let _ = Topcommon.add_directive "untrace"
+ (Directive_ident (dir_untrace Format.std_formatter))
+ {
+ section = Topdirs.section_trace;
+ doc = "Stop tracing the given function.";
+ }
+
+let _ = Topcommon.add_directive "untrace_all"
+ (Directive_none (dir_untrace_all Format.std_formatter))
+ {
+ section = Topdirs.section_trace;
+ doc = "Stop tracing all functions traced so far.";
+ }
+
+
+(* --- *)
+
+
let usage = "Usage: ocaml <options> <object-files> [script-file [arguments]]\n\
options are:"
@@ -37,15 +143,15 @@ let expand_position pos len =
first_nonexpanded_pos := pos + len + 2
let prepare ppf =
- Toploop.set_paths ();
+ Topcommon.set_paths ();
try
let res =
let objects =
List.rev (!preload_objects @ !Compenv.first_objfiles)
in
- List.for_all (Topdirs.load_file ppf) objects
+ List.for_all (Topeval.load_file false ppf) objects
in
- Toploop.run_hooks Toploop.Startup;
+ Topcommon.run_hooks Topcommon.Startup;
res
with x ->
try Location.report_exception ppf x; false
@@ -91,7 +197,7 @@ module Options = Main_args.Make_bytetop_options (struct
let _args = wrap_expand Arg.read_arg
let _args0 = wrap_expand Arg.read_arg0
let anonymous s = file_argument s
-end);;
+end)
let () =
let extra_paths =
diff --git a/toplevel/byte/trace.ml b/toplevel/byte/trace.ml
index 36839909fb..955bc2523c 100644
--- a/toplevel/byte/trace.ml
+++ b/toplevel/byte/trace.ml
@@ -19,7 +19,8 @@ open Format
open Misc
open Longident
open Types
-open Toploop
+open Topeval
+open Topcommon
type codeptr = Obj.raw_data
diff --git a/toplevel/dune b/toplevel/dune
index 9e7b745067..8c6c6a0381 100644
--- a/toplevel/dune
+++ b/toplevel/dune
@@ -19,7 +19,7 @@
(wrapped false)
(flags (:standard -principal -nostdlib))
(libraries stdlib ocamlcommon ocamlbytecomp)
- (modules genprintval toploop trace topdirs topmain))
+ (modules genprintval topeval trace topdirs toploop topmain))
(executable
(name topstart)
@@ -96,5 +96,5 @@
stdlib__Uchar
stdlib__Weak
; the rest
- outcometree topdirs toploop
+ outcometree topdirs topeval toploop topmain
)))
diff --git a/toplevel/native/topdirs.ml b/toplevel/native/topdirs.ml
deleted file mode 100644
index 8c5453f0d7..0000000000
--- a/toplevel/native/topdirs.ml
+++ /dev/null
@@ -1,224 +0,0 @@
-(**************************************************************************)
-(* *)
-(* OCaml *)
-(* *)
-(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
-(* *)
-(* Copyright 1996 Institut National de Recherche en Informatique et *)
-(* en Automatique. *)
-(* *)
-(* All rights reserved. This file is distributed under the terms of *)
-(* the GNU Lesser General Public License version 2.1, with the *)
-(* special exception on linking described in the file LICENSE. *)
-(* *)
-(**************************************************************************)
-
-(* Toplevel directives *)
-
-open Format
-open Misc
-open Longident
-open Types
-open Toploop
-
-(* The standard output formatter *)
-let std_out = std_formatter
-
-(* To quit *)
-
-let dir_quit () = raise (Compenv.Exit_with_status 0)
-
-let _ = Hashtbl.add directive_table "quit" (Directive_none dir_quit)
-
-(* To add a directory to the load path *)
-
-let dir_directory s =
- let d = expand_directory Config.standard_library s in
- let dir = Load_path.Dir.create d in
- Load_path.add dir;
- toplevel_env :=
- Stdlib.String.Set.fold
- (fun name env ->
- Env.add_persistent_structure (Ident.create_persistent name) env)
- (Env.persistent_structures_of_dir dir)
- !toplevel_env
-
-let _ = Hashtbl.add directive_table "directory" (Directive_string dir_directory)
-(* To remove a directory from the load path *)
-let dir_remove_directory s =
- let d = expand_directory Config.standard_library s in
- let keep id =
- match Load_path.find_uncap (Ident.name id ^ ".cmi") with
- | exception Not_found -> true
- | fn -> Filename.dirname fn <> d
- in
- toplevel_env := Env.filter_non_loaded_persistent keep !toplevel_env;
- Load_path.remove_dir s
-
-let _ =
- Hashtbl.add directive_table "remove_directory"
- (Directive_string dir_remove_directory)
-
-let _ = Hashtbl.add directive_table "show_dirs"
- (Directive_none
- (fun () ->
- List.iter print_endline (Load_path.get_paths ())
- ))
-
-(* To change the current directory *)
-
-let dir_cd s = Sys.chdir s
-
-let _ = Hashtbl.add directive_table "cd" (Directive_string dir_cd)
-
-(* Load in-core a .cmxs file *)
-
-let load_file ppf name0 =
- let name =
- try Some (Load_path.find name0)
- with Not_found -> None
- in
- match name with
- | None -> fprintf ppf "File not found: %s@." name0; false
- | Some name ->
- let fn,tmp =
- if Filename.check_suffix name ".cmx" || Filename.check_suffix name ".cmxa"
- then
- let cmxs = Filename.temp_file "caml" ".cmxs" in
- Asmlink.link_shared ~ppf_dump:ppf [name] cmxs;
- cmxs,true
- else
- name,false
- in
- let success =
- (* The Dynlink interface does not allow us to distinguish between
- a Dynlink.Error exceptions raised in the loaded modules
- or a genuine error during dynlink... *)
- try Dynlink.loadfile fn; true
- with
- | Dynlink.Error err ->
- fprintf ppf "Error while loading %s: %s.@."
- name (Dynlink.error_message err);
- false
- | exn ->
- print_exception_outcome ppf exn;
- false
- in
- if tmp then (try Sys.remove fn with Sys_error _ -> ());
- success
-
-
-let dir_load ppf name = ignore (load_file ppf name)
-
-let _ = Hashtbl.add directive_table "load" (Directive_string (dir_load std_out))
-
-(* Load commands from a file *)
-
-let dir_use ppf name = ignore(Toploop.use_file ppf name)
-let dir_use_output ppf name = ignore(Toploop.use_output ppf name)
-
-let _ = Hashtbl.add directive_table "use" (Directive_string (dir_use std_out))
-let _ = Hashtbl.add directive_table "use_output"
- (Directive_string (dir_use_output std_out))
-
-(* Install, remove a printer *)
-
-type 'a printer_type_new = Format.formatter -> 'a -> unit
-type 'a printer_type_old = 'a -> unit
-
-let match_printer_type ppf desc typename =
- let printer_type =
- match
- Env.find_type_by_name
- (Ldot(Lident "Topdirs", typename)) !toplevel_env
- with
- | (path, _) -> path
- | exception Not_found ->
- fprintf ppf "Cannot find type Topdirs.%s.@." typename;
- raise Exit
- in
- Ctype.begin_def();
- let ty_arg = Ctype.newvar() in
- Ctype.unify !toplevel_env
- (Ctype.newconstr printer_type [ty_arg])
- (Ctype.instance desc.val_type);
- Ctype.end_def();
- Ctype.generalize ty_arg;
- ty_arg
-
-let find_printer_type ppf lid =
- match Env.find_value_by_name lid !toplevel_env with
- | (path, desc) -> begin
- match match_printer_type ppf desc "printer_type_new" with
- | ty_arg -> (ty_arg, path, false)
- | exception Ctype.Unify _ -> begin
- match match_printer_type ppf desc "printer_type_old" with
- | ty_arg -> (ty_arg, path, true)
- | exception Ctype.Unify _ ->
- fprintf ppf "%a has a wrong type for a printing function.@."
- Printtyp.longident lid;
- raise Exit
- end
- end
- | exception Not_found ->
- fprintf ppf "Unbound value %a.@." Printtyp.longident lid;
- raise Exit
-
-let dir_install_printer ppf lid =
- try
- let (ty_arg, path, is_old_style) = find_printer_type ppf lid in
- let v = eval_value_path !toplevel_env path in
- let print_function =
- if is_old_style then
- (fun _formatter repr -> Obj.obj v (Obj.obj repr))
- else
- (fun formatter repr -> Obj.obj v formatter (Obj.obj repr)) in
- install_printer path ty_arg print_function
- with Exit -> ()
-
-let dir_remove_printer ppf lid =
- try
- let (_ty_arg, path, _is_old_style) = find_printer_type ppf lid in
- begin try
- remove_printer path
- with Not_found ->
- fprintf ppf "No printer named %a.@." Printtyp.longident lid
- end
- with Exit -> ()
-
-let _ = Hashtbl.add directive_table "install_printer"
- (Directive_ident (dir_install_printer std_out))
-let _ = Hashtbl.add directive_table "remove_printer"
- (Directive_ident (dir_remove_printer std_out))
-
-let parse_warnings ppf iserr s =
- try Warnings.parse_options iserr s
- with Arg.Bad err -> fprintf ppf "%s.@." err
-
-let unavailable () = invalid_arg "Directive unavailable in the native toplevel."
-
-let dir_trace _ _ = unavailable ()
-let dir_untrace _ _ = unavailable ()
-let dir_untrace_all _ _ = unavailable ()
-
-let _ =
-(* Control the printing of values *)
-
- Hashtbl.add directive_table "print_depth"
- (Directive_int(fun n -> max_printer_depth := n));
- Hashtbl.add directive_table "print_length"
- (Directive_int(fun n -> max_printer_steps := n));
-
-(* Set various compiler flags *)
-
- Hashtbl.add directive_table "labels"
- (Directive_bool(fun b -> Clflags.classic := not b));
-
- Hashtbl.add directive_table "principal"
- (Directive_bool(fun b -> Clflags.principal := b));
-
- Hashtbl.add directive_table "warnings"
- (Directive_string (parse_warnings std_out false));
-
- Hashtbl.add directive_table "warn_error"
- (Directive_string (parse_warnings std_out true))
diff --git a/toplevel/native/toploop.ml b/toplevel/native/topeval.ml
index 5b78073315..0a14a1c5da 100644
--- a/toplevel/native/toploop.ml
+++ b/toplevel/native/topeval.ml
@@ -22,7 +22,7 @@ open Parsetree
open Types
open Typedtree
open Outcometree
-open Ast_helper
+open Topcommon
type res = Ok of Obj.t | Err of string
type evaluation_outcome = Result of Obj.t | Exception of exn
@@ -53,18 +53,6 @@ let dll_run dll entry =
| Err s -> fatal_error ("Toploop.dll_run " ^ s)
-type directive_fun =
- | Directive_none of (unit -> unit)
- | Directive_string of (string -> unit)
- | Directive_int of (int -> unit)
- | Directive_ident of (Longident.t -> unit)
- | Directive_bool of (bool -> unit)
-
-type directive_info = {
- section: string;
- doc: string;
-}
-
let remembered = ref Ident.empty
let rec remember phrase_name i = function
@@ -137,96 +125,12 @@ module EvalPath = struct
let same_value v1 v2 = (v1 == v2)
end
-module Printer = Genprintval.Make(Obj)(EvalPath)
-
-let max_printer_depth = ref 100
-let max_printer_steps = ref 300
-
-let print_out_value = Oprint.out_value
-let print_out_type = Oprint.out_type
-let print_out_class_type = Oprint.out_class_type
-let print_out_module_type = Oprint.out_module_type
-let print_out_type_extension = Oprint.out_type_extension
-let print_out_sig_item = Oprint.out_sig_item
-let print_out_signature = Oprint.out_signature
-let print_out_phrase = Oprint.out_phrase
-
-let print_untyped_exception ppf obj =
- !print_out_value ppf (Printer.outval_of_untyped_exception obj)
-let outval_of_value env obj ty =
- Printer.outval_of_value !max_printer_steps !max_printer_depth
- (fun _ _ _ -> None) env obj ty
-let print_value env obj ppf ty =
- !print_out_value ppf (outval_of_value env obj ty)
-
-type ('a, 'b) gen_printer = ('a, 'b) Genprintval.gen_printer =
- | Zero of 'b
- | Succ of ('a -> ('a, 'b) gen_printer)
-
-let install_printer = Printer.install_printer
-let install_generic_printer = Printer.install_generic_printer
-let install_generic_printer' = Printer.install_generic_printer'
-let remove_printer = Printer.remove_printer
-
-(* Hooks for parsing functions *)
-
-let parse_toplevel_phrase = ref Parse.toplevel_phrase
-let parse_use_file = ref Parse.use_file
-let print_location = Location.print_loc
-let print_error = Location.print_report
-let print_warning = Location.print_warning
-let input_name = Location.input_name
-
-let parse_mod_use_file name lb =
- let modname =
- String.capitalize_ascii
- (Filename.remove_extension (Filename.basename name))
- in
- let items =
- List.concat
- (List.map
- (function Ptop_def s -> s | Ptop_dir _ -> [])
- (!parse_use_file lb))
- in
- [ Ptop_def
- [ Str.module_
- (Mb.mk
- (Location.mknoloc (Some modname))
- (Mod.structure items)
- )
- ]
- ]
-
-(* Hook for initialization *)
-
-let toplevel_startup_hook = ref (fun () -> ())
-
-type event = ..
-type event +=
- | Startup
- | After_setup
-
-let hooks = ref []
-
-let add_hook f = hooks := f :: !hooks
-
-let () =
- add_hook (function
- | Startup -> !toplevel_startup_hook ()
- | _ -> ())
-
-let run_hooks hook = List.iter (fun f -> f hook) !hooks
+include Topcommon.MakePrinter(Obj)(Genprintval.Make(Obj)(EvalPath))
(* Load in-core and execute a lambda term *)
let may_trace = ref false (* Global lock on tracing *)
-let backtrace = ref None
-
-let record_backtrace () =
- if Printexc.backtrace_status ()
- then backtrace := Some (Printexc.get_backtrace ())
-
let phrase_seqid = ref 0
let phrase_name = ref "TOP"
@@ -284,10 +188,8 @@ let load_lambda ppf ~module_ident ~required_globals lam size =
then Filename.concat (Sys.getcwd ()) dll
else dll in
match
- may_trace := true;
Fun.protect
~finally:(fun () ->
- may_trace := false;
(try Sys.remove dll with Sys_error _ -> ()))
(* note: under windows, cannot remove a loaded dll
(should remember the handles, close them in at_exit, and then
@@ -309,39 +211,6 @@ let pr_item =
| _ -> None
)
-(* The current typing environment for the toplevel *)
-
-let toplevel_env = ref Env.empty
-
-(* Print an exception produced by an evaluation *)
-
-let print_out_exception ppf exn outv =
- !print_out_phrase ppf (Ophr_exception (exn, outv))
-
-let print_exception_outcome ppf exn =
- if exn = Out_of_memory then Gc.full_major ();
- let outv = outval_of_value !toplevel_env (Obj.repr exn) Predef.type_exn in
- print_out_exception ppf exn outv;
- if Printexc.backtrace_status ()
- then
- match !backtrace with
- | None -> ()
- | Some b ->
- print_string b;
- backtrace := None
-
-(* The table of toplevel directives.
- Filled by functions from module topdirs. *)
-
-let directive_table = (Hashtbl.create 23 : (string, directive_fun) Hashtbl.t)
-
-let directive_info_table =
- (Hashtbl.create 23 : (string, directive_info) Hashtbl.t)
-
-let add_directive name dir_fun dir_info =
- Hashtbl.add directive_table name dir_fun;
- Hashtbl.add directive_info_table name dir_info
-
(* Execute a toplevel phrase *)
let execute_phrase print_outcome ppf phr =
@@ -432,11 +301,7 @@ let execute_phrase print_outcome ppf phr =
toplevel_env := oldenv; raise x
end
| Ptop_dir {pdir_name = {Location.txt = dir_name}; pdir_arg } ->
- let d =
- try Some (Hashtbl.find directive_table dir_name)
- with Not_found -> None
- in
- begin match d with
+ begin match get_directive dir_name with
| None ->
fprintf ppf "Unknown directive `%s'.@." dir_name;
false
@@ -465,260 +330,51 @@ let execute_phrase print_outcome ppf phr =
false
end
-(* Read and execute commands from a file, or from stdin if [name] is "". *)
-let use_print_results = ref true
+(* API compat *)
-let preprocess_phrase ppf phr =
- let phr =
- match phr with
- | Ptop_def str ->
- let str =
- Pparse.apply_rewriters_str ~restore:true ~tool_name:"ocaml" str
- in
- Ptop_def str
- | phr -> phr
+let getvalue _ = assert false
+let setvalue _ _ = assert false
+
+(* Loading files *)
+
+(* Load in-core a .cmxs file *)
+
+let load_file _ (* fixme *) ppf name0 =
+ let name =
+ try Some (Load_path.find name0)
+ with Not_found -> None
in
- if !Clflags.dump_parsetree then Printast.top_phrase ppf phr;
- if !Clflags.dump_source then Pprintast.top_phrase ppf phr;
- phr
-
-let use_channel ppf ~wrap_in_module ic name filename =
- let lb = Lexing.from_channel ic in
- Location.init lb filename;
- (* Skip initial #! line if any *)
- Lexer.skip_hash_bang lb;
- let success =
- protect_refs [ R (Location.input_name, filename) ] (fun () ->
- try
- List.iter
- (fun ph ->
- let ph = preprocess_phrase ppf ph in
- if not (execute_phrase !use_print_results ppf ph) then raise Exit)
- (if wrap_in_module then
- parse_mod_use_file name lb
- else
- !parse_use_file lb);
- true
- with
- | Exit -> false
- | Sys.Break -> fprintf ppf "Interrupted.@."; false
- | x -> Location.report_exception ppf x; false) in
- success
-
-let use_output ppf command =
- let fn = Filename.temp_file "ocaml" "_toploop.ml" in
- Misc.try_finally ~always:(fun () ->
- try Sys.remove fn with Sys_error _ -> ())
- (fun () ->
- match
- Printf.ksprintf Sys.command "%s > %s"
- command
- (Filename.quote fn)
- with
- | 0 ->
- let ic = open_in_bin fn in
- Misc.try_finally ~always:(fun () -> close_in ic)
- (fun () ->
- use_channel ppf ~wrap_in_module:false ic "" "(command-output)")
- | n ->
- fprintf ppf "Command exited with code %d.@." n;
- false)
-
-let use_file ppf ~wrap_in_module name =
match name with
- | "" ->
- use_channel ppf ~wrap_in_module stdin name "(stdin)"
- | _ ->
- match Load_path.find name with
- | filename ->
- let ic = open_in_bin filename in
- Misc.try_finally ~always:(fun () -> close_in ic)
- (fun () -> use_channel ppf ~wrap_in_module ic name filename)
- | exception Not_found ->
- fprintf ppf "Cannot find file %s.@." name;
- false
-
-let mod_use_file ppf name =
- use_file ppf ~wrap_in_module:true name
-let use_file ppf name =
- use_file ppf ~wrap_in_module:false name
-
-let use_silently ppf name =
- protect_refs [ R (use_print_results, false) ] (fun () -> use_file ppf name)
-
-(* Reading function for interactive use *)
-
-let first_line = ref true
-let got_eof = ref false;;
-
-let read_input_default prompt buffer len =
- output_string stdout prompt; flush stdout;
- let i = ref 0 in
- try
- while true do
- if !i >= len then raise Exit;
- let c = input_char stdin in
- Bytes.set buffer !i c;
- incr i;
- if c = '\n' then raise Exit;
- done;
- (!i, false)
- with
- | End_of_file ->
- (!i, true)
- | Exit ->
- (!i, false)
-
-let read_interactive_input = ref read_input_default
-
-let refill_lexbuf buffer len =
- if !got_eof then (got_eof := false; 0) else begin
- let prompt =
- if !Clflags.noprompt then ""
- else if !first_line then "# "
- else if !Clflags.nopromptcont then ""
- else if Lexer.in_comment () then "* "
- else " "
+ | None -> fprintf ppf "File not found: %s@." name0; false
+ | Some name ->
+ let fn,tmp =
+ if Filename.check_suffix name ".cmx" || Filename.check_suffix name ".cmxa"
+ then
+ let cmxs = Filename.temp_file "caml" ".cmxs" in
+ Asmlink.link_shared ~ppf_dump:ppf [name] cmxs;
+ cmxs,true
+ else
+ name,false
+ in
+ let success =
+ (* The Dynlink interface does not allow us to distinguish between
+ a Dynlink.Error exceptions raised in the loaded modules
+ or a genuine error during dynlink... *)
+ try Dynlink.loadfile fn; true
+ with
+ | Dynlink.Error err ->
+ fprintf ppf "Error while loading %s: %s.@."
+ name (Dynlink.error_message err);
+ false
+ | exn ->
+ print_exception_outcome ppf exn;
+ false
in
- first_line := false;
- let (len, eof) = !read_interactive_input prompt buffer len in
- if eof then begin
- Location.echo_eof ();
- if len > 0 then got_eof := true;
- len
- end else
- len
- end
-
-(* Toplevel initialization. Performed here instead of at the
- beginning of loop() so that user code linked in with ocamlmktop
- can call directives from Topdirs. *)
-
-let _ =
- Sys.interactive := true;
+ if tmp then (try Sys.remove fn with Sys_error _ -> ());
+ success
+
+let init () =
Compmisc.init_path ();
Clflags.dlcode := true;
()
-
-let find_ocamlinit () =
- let ocamlinit = ".ocamlinit" in
- if Sys.file_exists ocamlinit then Some ocamlinit else
- let getenv var = match Sys.getenv var with
- | exception Not_found -> None | "" -> None | v -> Some v
- in
- let exists_in_dir dir file = match dir with
- | None -> None
- | Some dir ->
- let file = Filename.concat dir file in
- if Sys.file_exists file then Some file else None
- in
- let home_dir () = getenv "HOME" in
- let config_dir () =
- if Sys.win32 then None else
- match getenv "XDG_CONFIG_HOME" with
- | Some _ as v -> v
- | None ->
- match home_dir () with
- | None -> None
- | Some dir -> Some (Filename.concat dir ".config")
- in
- let init_ml = Filename.concat "ocaml" "init.ml" in
- match exists_in_dir (config_dir ()) init_ml with
- | Some _ as v -> v
- | None -> exists_in_dir (home_dir ()) ocamlinit
-
-let load_ocamlinit ppf =
- if !Clflags.noinit then ()
- else match !Clflags.init_file with
- | Some f -> if Sys.file_exists f then ignore (use_silently ppf f)
- else fprintf ppf "Init file not found: \"%s\".@." f
- | None ->
- match find_ocamlinit () with
- | None -> ()
- | Some file -> ignore (use_silently ppf file)
-;;
-
-let set_paths () =
- (* Add whatever -I options have been specified on the command line,
- but keep the directories that user code linked in with ocamlmktop
- may have added to load_path. *)
- let expand = Misc.expand_directory Config.standard_library in
- let current_load_path = Load_path.get_paths () in
- let load_path = List.concat [
- [ "" ];
- List.map expand (List.rev !Compenv.first_include_dirs);
- List.map expand (List.rev !Clflags.include_dirs);
- List.map expand (List.rev !Compenv.last_include_dirs);
- current_load_path;
- [expand "+camlp4"];
- ]
- in
- Load_path.init load_path
-
-let initialize_toplevel_env () =
- toplevel_env := Compmisc.initial_env()
-
-(* The interactive loop *)
-
-exception PPerror
-
-let loop ppf =
- Location.formatter_for_warnings := ppf;
- if not !Clflags.noversion then
- fprintf ppf " OCaml version %s - native toplevel@.@." Config.version;
- initialize_toplevel_env ();
- let lb = Lexing.from_function refill_lexbuf in
- Location.init lb "//toplevel//";
- Location.input_name := "//toplevel//";
- Location.input_lexbuf := Some lb;
- Sys.catch_break true;
- run_hooks After_setup;
- load_ocamlinit ppf;
- while true do
- let snap = Btype.snapshot () in
- try
- Lexing.flush_input lb;
- Location.reset();
- first_line := true;
- let phr = try !parse_toplevel_phrase lb with Exit -> raise PPerror in
- let phr = preprocess_phrase ppf phr in
- Env.reset_cache_toplevel ();
- if !Clflags.dump_parsetree then Printast.top_phrase ppf phr;
- if !Clflags.dump_source then Pprintast.top_phrase ppf phr;
- ignore(execute_phrase true ppf phr)
- with
- | End_of_file -> raise (Compenv.Exit_with_status 0)
- | Sys.Break -> fprintf ppf "Interrupted.@."; Btype.backtrack snap
- | PPerror -> ()
- | x -> Location.report_exception ppf x; Btype.backtrack snap
- done
-
-external caml_sys_modify_argv : string array -> unit =
- "caml_sys_modify_argv"
-
-let override_sys_argv new_argv =
- caml_sys_modify_argv new_argv;
- Arg.current := 0
-
-(* Execute a script. If [name] is "", read the script from stdin. *)
-
-let run_script ppf name args =
- override_sys_argv args;
- Compmisc.init_path ~dir:(Filename.dirname name) ();
- (* Note: would use [Filename.abspath] here, if we had it. *)
- toplevel_env := Compmisc.initial_env();
- Sys.interactive := false;
- run_hooks After_setup;
- let explicit_name =
- (* Prevent use_silently from searching in the path. *)
- if Filename.is_implicit name
- then Filename.concat Filename.current_dir_name name
- else name
- in
- use_silently ppf explicit_name
-
-(* API compat *)
-
-let getvalue _ = assert false
-let setvalue _ _ = assert false
diff --git a/toplevel/native/topmain.ml b/toplevel/native/topmain.ml
index 4828bce83e..10feb68ea7 100644
--- a/toplevel/native/topmain.ml
+++ b/toplevel/native/topmain.ml
@@ -13,10 +13,8 @@
(* *)
(**************************************************************************)
-open Compenv
-
-let usage =
- "Usage: ocamlnat <options> <object-files> [script-file]\noptions are:"
+let usage = "Usage: ocamlnat <options> <object-files> [script-file]\n\
+ options are:"
let preload_objects = ref []
@@ -40,12 +38,12 @@ let expand_position pos len =
let prepare ppf =
- Toploop.set_paths ();
+ Topcommon.set_paths ();
try
let res =
- List.for_all (Topdirs.load_file ppf) (List.rev !preload_objects)
+ List.for_all (Topeval.load_file false ppf) (List.rev !preload_objects)
in
- Toploop.run_hooks Toploop.Startup;
+ Topcommon.run_hooks Topcommon.Startup;
res
with x ->
try Location.report_exception ppf x; false
@@ -67,15 +65,15 @@ let file_argument name =
Printf.eprintf "For implementation reasons, the toplevel does not support\
\ having script files (here %S) inside expanded arguments passed through\
\ the -args{,0} command-line option.\n" name;
- raise (Exit_with_status 2)
+ raise (Compenv.Exit_with_status 2)
end else begin
let newargs = Array.sub !argv !Arg.current
(Array.length !argv - !Arg.current)
in
Compmisc.read_clflags_from_env ();
if prepare ppf && Toploop.run_script ppf name newargs
- then raise (Exit_with_status 0)
- else raise (Exit_with_status 2)
+ then raise (Compenv.Exit_with_status 0)
+ else raise (Compenv.Exit_with_status 2)
end
let wrap_expand f s =
@@ -108,16 +106,16 @@ let main () =
Arg.parse_and_expand_argv_dynamic current argv list file_argument usage;
with
| Arg.Bad msg -> Format.fprintf Format.err_formatter "%s%!" msg;
- raise (Exit_with_status 2)
+ raise (Compenv.Exit_with_status 2)
| Arg.Help msg -> Format.fprintf Format.std_formatter "%s%!" msg;
- raise (Exit_with_status 0)
+ raise (Compenv.Exit_with_status 0)
end;
Compmisc.read_clflags_from_env ();
- if not (prepare Format.err_formatter) then raise (Exit_with_status 2);
+ if not (prepare Format.err_formatter) then raise (Compenv.Exit_with_status 2);
Compmisc.init_path ();
Toploop.loop Format.std_formatter
let main () =
match main () with
- | exception Exit_with_status n -> n
+ | exception Compenv.Exit_with_status n -> n
| () -> 0
diff --git a/toplevel/topcommon.ml b/toplevel/topcommon.ml
new file mode 100644
index 0000000000..103872e9e9
--- /dev/null
+++ b/toplevel/topcommon.ml
@@ -0,0 +1,302 @@
+(**************************************************************************)
+(* *)
+(* OCaml *)
+(* *)
+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
+(* *)
+(* Copyright 1996 Institut National de Recherche en Informatique et *)
+(* en Automatique. *)
+(* *)
+(* All rights reserved. This file is distributed under the terms of *)
+(* the GNU Lesser General Public License version 2.1, with the *)
+(* special exception on linking described in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(* Definitions for the interactive toplevel loop that are common between
+ bytecode and native *)
+
+open Format
+open Parsetree
+open Outcometree
+open Ast_helper
+
+(* Hooks for parsing functions *)
+
+let parse_toplevel_phrase = ref Parse.toplevel_phrase
+let parse_use_file = ref Parse.use_file
+let print_location = Location.print_loc
+let print_error = Location.print_report
+let print_warning = Location.print_warning
+let input_name = Location.input_name
+
+let parse_mod_use_file name lb =
+ let modname =
+ String.capitalize_ascii
+ (Filename.remove_extension (Filename.basename name))
+ in
+ let items =
+ List.concat
+ (List.map
+ (function Ptop_def s -> s | Ptop_dir _ -> [])
+ (!parse_use_file lb))
+ in
+ [ Ptop_def
+ [ Str.module_
+ (Mb.mk
+ (Location.mknoloc (Some modname))
+ (Mod.structure items)
+ )
+ ]
+ ]
+
+(* Hooks for printing *)
+
+let max_printer_depth = ref 100
+let max_printer_steps = ref 300
+
+let print_out_value = Oprint.out_value
+let print_out_type = Oprint.out_type
+let print_out_class_type = Oprint.out_class_type
+let print_out_module_type = Oprint.out_module_type
+let print_out_type_extension = Oprint.out_type_extension
+let print_out_sig_item = Oprint.out_sig_item
+let print_out_signature = Oprint.out_signature
+let print_out_phrase = Oprint.out_phrase
+
+
+(* The current typing environment for the toplevel *)
+
+let toplevel_env = ref Env.empty
+
+let backtrace = ref None
+
+(* Generic printer *)
+
+module type PRINTER = sig
+
+ module Printer: Genprintval.S
+
+ val print_value: Env.t -> Printer.t -> formatter -> Types.type_expr -> unit
+ val print_untyped_exception: formatter -> Printer.t -> unit
+
+ val print_exception_outcome : formatter -> exn -> unit
+
+ val outval_of_value:
+ Env.t -> Printer.t -> Types.type_expr -> Outcometree.out_value
+
+ type ('a, 'b) gen_printer =
+ | Zero of 'b
+ | Succ of ('a -> ('a, 'b) gen_printer)
+
+ val install_printer :
+ Path.t -> Types.type_expr -> (formatter -> Printer.t -> unit) -> unit
+ val install_generic_printer :
+ Path.t -> Path.t ->
+ (int -> (int -> Printer.t -> Outcometree.out_value,
+ Printer.t-> Outcometree.out_value) gen_printer) -> unit
+ val install_generic_printer' :
+ Path.t -> Path.t -> (formatter -> Printer.t -> unit,
+ formatter -> Printer.t -> unit) gen_printer -> unit
+ val remove_printer : Path.t -> unit
+
+end
+
+module MakePrinter
+ (O: Genprintval.OBJ)
+ (Printer: Genprintval.S with type t = O.t)
+ : PRINTER with type Printer.t = O.t
+= struct
+
+ module Printer = Printer
+
+ let print_untyped_exception ppf obj =
+ !print_out_value ppf (Printer.outval_of_untyped_exception obj)
+ let outval_of_value env obj ty =
+ Printer.outval_of_value !max_printer_steps !max_printer_depth
+ (fun _ _ _ -> None) env obj ty
+ let print_value env obj ppf ty =
+ !print_out_value ppf (outval_of_value env obj ty)
+
+ (* Print an exception produced by an evaluation *)
+
+ let print_out_exception ppf exn outv =
+ !print_out_phrase ppf (Ophr_exception (exn, outv))
+
+ let print_exception_outcome ppf exn =
+ if exn = Out_of_memory then Gc.full_major ();
+ let outv = outval_of_value !toplevel_env (O.repr exn) Predef.type_exn in
+ print_out_exception ppf exn outv;
+ if Printexc.backtrace_status ()
+ then
+ match !backtrace with
+ | None -> ()
+ | Some b ->
+ print_string b;
+ backtrace := None
+
+ type ('a, 'b) gen_printer = ('a, 'b) Genprintval.gen_printer =
+ | Zero of 'b
+ | Succ of ('a -> ('a, 'b) gen_printer)
+
+ let install_printer = Printer.install_printer
+ let install_generic_printer = Printer.install_generic_printer
+ let install_generic_printer' = Printer.install_generic_printer'
+ let remove_printer = Printer.remove_printer
+
+end
+
+
+(* Hook for initialization *)
+
+let toplevel_startup_hook = ref (fun () -> ())
+
+type event = ..
+type event +=
+ | Startup
+ | After_setup
+
+let hooks = ref []
+
+let add_hook f = hooks := f :: !hooks
+
+let () =
+ add_hook (function
+ | Startup -> !toplevel_startup_hook ()
+ | _ -> ())
+
+let run_hooks hook = List.iter (fun f -> f hook) !hooks
+
+(* Helpers for execution *)
+
+type evaluation_outcome = Result of Obj.t | Exception of exn
+
+let record_backtrace () =
+ if Printexc.backtrace_status ()
+ then backtrace := Some (Printexc.get_backtrace ())
+
+let preprocess_phrase ppf phr =
+ let phr =
+ match phr with
+ | Ptop_def str ->
+ let str =
+ Pparse.apply_rewriters_str ~restore:true ~tool_name:"ocaml" str
+ in
+ Ptop_def str
+ | phr -> phr
+ in
+ if !Clflags.dump_parsetree then Printast.top_phrase ppf phr;
+ if !Clflags.dump_source then Pprintast.top_phrase ppf phr;
+ phr
+
+(* Phrase buffer that stores the last toplevel phrase (see
+ [Location.input_phrase_buffer]). *)
+let phrase_buffer = Buffer.create 1024
+
+(* Reading function for interactive use *)
+
+let first_line = ref true
+let got_eof = ref false
+
+let read_input_default prompt buffer len =
+ output_string stdout prompt; flush stdout;
+ let i = ref 0 in
+ try
+ while true do
+ if !i >= len then raise Exit;
+ let c = input_char stdin in
+ Bytes.set buffer !i c;
+ (* Also populate the phrase buffer as new characters are added. *)
+ Buffer.add_char phrase_buffer c;
+ incr i;
+ if c = '\n' then raise Exit;
+ done;
+ (!i, false)
+ with
+ | End_of_file ->
+ (!i, true)
+ | Exit ->
+ (!i, false)
+
+let read_interactive_input = ref read_input_default
+
+let refill_lexbuf buffer len =
+ if !got_eof then (got_eof := false; 0) else begin
+ let prompt =
+ if !Clflags.noprompt then ""
+ else if !first_line then "# "
+ else if !Clflags.nopromptcont then ""
+ else if Lexer.in_comment () then "* "
+ else " "
+ in
+ first_line := false;
+ let (len, eof) = !read_interactive_input prompt buffer len in
+ if eof then begin
+ Location.echo_eof ();
+ if len > 0 then got_eof := true;
+ len
+ end else
+ len
+ end
+
+let set_paths () =
+ (* Add whatever -I options have been specified on the command line,
+ but keep the directories that user code linked in with ocamlmktop
+ may have added to load_path. *)
+ let expand = Misc.expand_directory Config.standard_library in
+ let current_load_path = Load_path.get_paths () in
+ let load_path = List.concat [
+ [ "" ];
+ List.map expand (List.rev !Compenv.first_include_dirs);
+ List.map expand (List.rev !Clflags.include_dirs);
+ List.map expand (List.rev !Compenv.last_include_dirs);
+ current_load_path;
+ [expand "+camlp4"];
+ ]
+ in
+ Load_path.init load_path;
+ Dll.add_path load_path
+
+let initialize_toplevel_env () =
+ toplevel_env := Compmisc.initial_env()
+
+external caml_sys_modify_argv : string array -> unit =
+ "caml_sys_modify_argv"
+
+let override_sys_argv new_argv =
+ caml_sys_modify_argv new_argv;
+ Arg.current := 0
+
+
+(* The table of toplevel directives.
+ Filled by functions from module topdirs. *)
+
+type directive_fun =
+ | Directive_none of (unit -> unit)
+ | Directive_string of (string -> unit)
+ | Directive_int of (int -> unit)
+ | Directive_ident of (Longident.t -> unit)
+ | Directive_bool of (bool -> unit)
+
+type directive_info = {
+ section: string;
+ doc: string;
+}
+
+let directive_table = (Hashtbl.create 23 : (string, directive_fun) Hashtbl.t)
+
+let directive_info_table =
+ (Hashtbl.create 23 : (string, directive_info) Hashtbl.t)
+
+let add_directive name dir_fun dir_info =
+ Hashtbl.add directive_table name dir_fun;
+ Hashtbl.add directive_info_table name dir_info
+
+let get_directive name =
+ Hashtbl.find_opt directive_table name
+
+let get_directive_info name =
+ Hashtbl.find_opt directive_info_table name
+
+let all_directive_names () =
+ Hashtbl.fold (fun dir _ acc -> dir::acc) directive_table []
diff --git a/toplevel/topcommon.mli b/toplevel/topcommon.mli
new file mode 100644
index 0000000000..1cf0f63c2c
--- /dev/null
+++ b/toplevel/topcommon.mli
@@ -0,0 +1,198 @@
+(**************************************************************************)
+(* *)
+(* OCaml *)
+(* *)
+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
+(* *)
+(* Copyright 1996 Institut National de Recherche en Informatique et *)
+(* en Automatique. *)
+(* *)
+(* All rights reserved. This file is distributed under the terms of *)
+(* the GNU Lesser General Public License version 2.1, with the *)
+(* special exception on linking described in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(** This module provides common implementations for internals of [Toploop], for
+ bytecode and native code (see [Topeval] for the diverging parts of the
+ implementation).
+
+ You should not use it directly, refer to the functions in [Toploop] instead.
+*)
+
+(**/**)
+
+(* Definitions for the interactive toplevel loop that are common between
+ bytecode and native *)
+
+open Format
+
+(* Set the load paths, before running anything *)
+
+val set_paths : unit -> unit
+
+(* Management and helpers for the execution *)
+
+val toplevel_env : Env.t ref
+ (* Typing environment for the toplevel *)
+val initialize_toplevel_env : unit -> unit
+ (* Initialize the typing environment for the toplevel *)
+val preprocess_phrase :
+ formatter -> Parsetree.toplevel_phrase -> Parsetree.toplevel_phrase
+ (* Preprocess the given toplevel phrase using regular and ppx
+ preprocessors. Return the updated phrase. *)
+val record_backtrace : unit -> unit
+
+
+(* Printing of values *)
+
+val max_printer_depth: int ref
+val max_printer_steps: int ref
+
+val print_out_value :
+ (formatter -> Outcometree.out_value -> unit) ref
+val print_out_type :
+ (formatter -> Outcometree.out_type -> unit) ref
+val print_out_class_type :
+ (formatter -> Outcometree.out_class_type -> unit) ref
+val print_out_module_type :
+ (formatter -> Outcometree.out_module_type -> unit) ref
+val print_out_type_extension :
+ (formatter -> Outcometree.out_type_extension -> unit) ref
+val print_out_sig_item :
+ (formatter -> Outcometree.out_sig_item -> unit) ref
+val print_out_signature :
+ (formatter -> Outcometree.out_sig_item list -> unit) ref
+val print_out_phrase :
+ (formatter -> Outcometree.out_phrase -> unit) ref
+
+module type PRINTER = sig
+
+ module Printer: Genprintval.S
+
+ val print_value: Env.t -> Printer.t -> formatter -> Types.type_expr -> unit
+
+ val print_untyped_exception: formatter -> Printer.t -> unit
+
+ val print_exception_outcome : formatter -> exn -> unit
+ (* Print an exception resulting from the evaluation of user code. *)
+
+ val outval_of_value:
+ Env.t -> Printer.t -> Types.type_expr -> Outcometree.out_value
+
+ type ('a, 'b) gen_printer =
+ | Zero of 'b
+ | Succ of ('a -> ('a, 'b) gen_printer)
+
+ val install_printer :
+ Path.t -> Types.type_expr -> (formatter -> Printer.t -> unit) -> unit
+ val install_generic_printer :
+ Path.t -> Path.t ->
+ (int -> (int -> Printer.t -> Outcometree.out_value,
+ Printer.t-> Outcometree.out_value) gen_printer) -> unit
+ val install_generic_printer' :
+ Path.t -> Path.t -> (formatter -> Printer.t -> unit,
+ formatter -> Printer.t -> unit) gen_printer -> unit
+ val remove_printer : Path.t -> unit
+
+end
+
+module MakePrinter (O : Genprintval.OBJ) (P : Genprintval.S with type t = O.t):
+ PRINTER with module Printer = P
+ and type Printer.t = O.t
+
+(* Interface with toplevel directives *)
+
+type directive_fun =
+ | Directive_none of (unit -> unit)
+ | Directive_string of (string -> unit)
+ | Directive_int of (int -> unit)
+ | Directive_ident of (Longident.t -> unit)
+ | Directive_bool of (bool -> unit)
+
+type directive_info = {
+ section: string;
+ doc: string;
+}
+
+(* Add toplevel directive and its documentation.
+ @since 4.03 *)
+val add_directive : string -> directive_fun -> directive_info -> unit
+
+val get_directive : string -> directive_fun option
+
+val get_directive_info : string -> directive_info option
+
+val all_directive_names : unit -> string list
+
+val[@deprecated] directive_table : (string, directive_fun) Hashtbl.t
+ (* @deprecated please use [add_directive] instead of inserting
+ in this table directly. *)
+
+val[@deprecated] directive_info_table : (string, directive_info) Hashtbl.t
+ (* @deprecated please use [add_directive] instead of inserting
+ in this table directly. *)
+
+(* Hooks for external parsers and printers *)
+
+val parse_toplevel_phrase : (Lexing.lexbuf -> Parsetree.toplevel_phrase) ref
+val parse_use_file : (Lexing.lexbuf -> Parsetree.toplevel_phrase list) ref
+val print_location : formatter -> Location.t -> unit
+val print_error : formatter -> Location.error -> unit
+val print_warning : Location.t -> formatter -> Warnings.t -> unit
+val input_name : string ref
+
+(* Hooks for external line editor *)
+
+(* Phrase buffer that stores the last toplevel phrase (see
+ [Location.input_phrase_buffer]). *)
+val phrase_buffer : Buffer.t
+
+val first_line : bool ref
+
+val got_eof : bool ref
+
+val read_interactive_input : (string -> bytes -> int -> int * bool) ref
+
+(* Hooks *)
+
+val toplevel_startup_hook : (unit -> unit) ref
+
+type event = ..
+type event +=
+ | Startup
+ | After_setup
+ (* Just after the setup, when the toplevel is ready to evaluate user
+ input. This happens before the toplevel has evaluated any kind of
+ user input, in particular this happens before loading the
+ [.ocamlinit] file. *)
+
+val add_hook : (event -> unit) -> unit
+(* Add a function that will be called at key points of the toplevel
+ initialization process. *)
+
+val run_hooks : event -> unit
+(* Run all the registered hooks. *)
+
+(* Misc *)
+
+val override_sys_argv : string array -> unit
+(* [override_sys_argv args] replaces the contents of [Sys.argv] by [args]
+ and reset [Arg.current] to [0].
+
+ This is called by [run_script] so that [Sys.argv] represents
+ "script.ml args..." instead of the full command line:
+ "ocamlrun unix.cma ... script.ml args...". *)
+
+(**/**)
+
+(* internal functions used by [Topeval] *)
+
+type evaluation_outcome = Result of Obj.t | Exception of exn
+
+val backtrace: string option ref
+
+val parse_mod_use_file:
+ string -> Lexing.lexbuf -> Parsetree.toplevel_phrase list
+
+val refill_lexbuf: bytes -> int -> int
diff --git a/toplevel/byte/topdirs.ml b/toplevel/topdirs.ml
index 6fbbc6c13d..94e066d1d0 100644
--- a/toplevel/byte/topdirs.ml
+++ b/toplevel/topdirs.ml
@@ -19,8 +19,6 @@ open Format
open Misc
open Longident
open Types
-open Cmo_format
-open Trace
open Toploop
(* The standard output formatter *)
@@ -104,6 +102,16 @@ let _ = add_directive "remove_directory" (Directive_string dir_remove_directory)
section = section_run;
doc = "Remove the given directory from the search path.";
}
+
+let dir_show_dirs () =
+ List.iter print_endline (Load_path.get_paths ())
+
+let _ = add_directive "show_dirs" (Directive_none dir_show_dirs)
+ {
+ section = section_run;
+ doc = "List directories currently in the search path.";
+ }
+
(* To change the current directory *)
let dir_cd s = Sys.chdir s
@@ -113,112 +121,8 @@ let _ = add_directive "cd" (Directive_string dir_cd)
section = section_run;
doc = "Change the current working directory.";
}
-(* Load in-core a .cmo file *)
-
-exception Load_failed
-
-let check_consistency ppf filename cu =
- try Env.import_crcs ~source:filename cu.cu_imports
- with Persistent_env.Consistbl.Inconsistency {
- unit_name = name;
- inconsistent_source = user;
- original_source = auth;
- } ->
- fprintf ppf "@[<hv 0>The files %s@ and %s@ \
- disagree over interface %s@]@."
- user auth name;
- raise Load_failed
-
-let load_compunit ic filename ppf compunit =
- check_consistency ppf filename compunit;
- seek_in ic compunit.cu_pos;
- let code_size = compunit.cu_codesize + 8 in
- let code = LongString.create code_size in
- LongString.input_bytes_into code ic compunit.cu_codesize;
- LongString.set code compunit.cu_codesize (Char.chr Opcodes.opRETURN);
- LongString.blit_string "\000\000\000\001\000\000\000" 0
- code (compunit.cu_codesize + 1) 7;
- let initial_symtable = Symtable.current_state() in
- Symtable.patch_object code compunit.cu_reloc;
- Symtable.update_global_table();
- let events =
- if compunit.cu_debug = 0 then [| |]
- else begin
- seek_in ic compunit.cu_debug;
- [| input_value ic |]
- end in
- begin try
- may_trace := true;
- let _bytecode, closure = Meta.reify_bytecode code events None in
- ignore (closure ());
- may_trace := false;
- with exn ->
- record_backtrace ();
- may_trace := false;
- Symtable.restore_state initial_symtable;
- print_exception_outcome ppf exn;
- raise Load_failed
- end
-let rec load_file recursive ppf name =
- let filename =
- try Some (Load_path.find name) with Not_found -> None
- in
- match filename with
- | None -> fprintf ppf "Cannot find file %s.@." name; false
- | Some filename ->
- let ic = open_in_bin filename in
- Misc.try_finally
- ~always:(fun () -> close_in ic)
- (fun () -> really_load_file recursive ppf name filename ic)
-
-and really_load_file recursive ppf name filename ic =
- let buffer = really_input_string ic (String.length Config.cmo_magic_number) in
- try
- if buffer = Config.cmo_magic_number then begin
- let compunit_pos = input_binary_int ic in (* Go to descriptor *)
- seek_in ic compunit_pos;
- let cu : compilation_unit = input_value ic in
- if recursive then
- List.iter
- (function
- | (Reloc_getglobal id, _)
- when not (Symtable.is_global_defined id) ->
- let file = Ident.name id ^ ".cmo" in
- begin match Load_path.find_uncap file with
- | exception Not_found -> ()
- | file ->
- if not (load_file recursive ppf file) then raise Load_failed
- end
- | _ -> ()
- )
- cu.cu_reloc;
- load_compunit ic filename ppf cu;
- true
- end else
- if buffer = Config.cma_magic_number then begin
- let toc_pos = input_binary_int ic in (* Go to table of contents *)
- seek_in ic toc_pos;
- let lib = (input_value ic : library) in
- List.iter
- (fun dllib ->
- let name = Dll.extract_dll_name dllib in
- try Dll.open_dlls Dll.For_execution [name]
- with Failure reason ->
- fprintf ppf
- "Cannot load required shared library %s.@.Reason: %s.@."
- name reason;
- raise Load_failed)
- lib.lib_dllibs;
- List.iter (load_compunit ic filename ppf) lib.lib_units;
- true
- end else begin
- fprintf ppf "File %s is not a bytecode object file.@." name;
- false
- end
- with Load_failed -> false
-
-let dir_load ppf name = ignore (load_file false ppf name)
+let dir_load ppf name = ignore (Topeval.load_file false ppf name)
let _ = add_directive "load" (Directive_string (dir_load std_out))
{
@@ -226,7 +130,7 @@ let _ = add_directive "load" (Directive_string (dir_load std_out))
doc = "Load in memory a bytecode object, produced by ocamlc.";
}
-let dir_load_rec ppf name = ignore (load_file true ppf name)
+let dir_load_rec ppf name = ignore (Topeval.load_file true ppf name)
let _ = add_directive "load_rec"
(Directive_string (dir_load_rec std_out))
@@ -235,7 +139,7 @@ let _ = add_directive "load_rec"
doc = "As #load, but loads dependencies recursively.";
}
-let load_file = load_file false
+let load_file = Topeval.load_file false
(* Load commands from a file *)
@@ -413,78 +317,6 @@ let _ = add_directive "remove_printer"
doc = "Remove the named function from the table of toplevel printers.";
}
-(* The trace *)
-
-external current_environment: unit -> Obj.t = "caml_get_current_environment"
-
-let tracing_function_ptr =
- get_code_pointer
- (Obj.repr (fun arg -> Trace.print_trace (current_environment()) arg))
-
-let dir_trace ppf lid =
- match Env.find_value_by_name lid !toplevel_env with
- | (path, desc) -> begin
- (* Check if this is a primitive *)
- match desc.val_kind with
- | Val_prim _ ->
- fprintf ppf "%a is an external function and cannot be traced.@."
- Printtyp.longident lid
- | _ ->
- let clos = eval_value_path !toplevel_env path in
- (* Nothing to do if it's not a closure *)
- if Obj.is_block clos
- && (Obj.tag clos = Obj.closure_tag || Obj.tag clos = Obj.infix_tag)
- && (match Ctype.(repr (expand_head !toplevel_env desc.val_type))
- with {desc=Tarrow _} -> true | _ -> false)
- then begin
- match is_traced clos with
- | Some opath ->
- fprintf ppf "%a is already traced (under the name %a).@."
- Printtyp.path path
- Printtyp.path opath
- | None ->
- (* Instrument the old closure *)
- traced_functions :=
- { path = path;
- closure = clos;
- actual_code = get_code_pointer clos;
- instrumented_fun =
- instrument_closure !toplevel_env lid ppf desc.val_type }
- :: !traced_functions;
- (* Redirect the code field of the closure to point
- to the instrumentation function *)
- set_code_pointer clos tracing_function_ptr;
- fprintf ppf "%a is now traced.@." Printtyp.longident lid
- end else fprintf ppf "%a is not a function.@." Printtyp.longident lid
- end
- | exception Not_found ->
- fprintf ppf "Unbound value %a.@." Printtyp.longident lid
-
-let dir_untrace ppf lid =
- match Env.find_value_by_name lid !toplevel_env with
- | (path, _desc) ->
- let rec remove = function
- | [] ->
- fprintf ppf "%a was not traced.@." Printtyp.longident lid;
- []
- | f :: rem ->
- if Path.same f.path path then begin
- set_code_pointer f.closure f.actual_code;
- fprintf ppf "%a is no longer traced.@." Printtyp.longident lid;
- rem
- end else f :: remove rem in
- traced_functions := remove !traced_functions
- | exception Not_found ->
- fprintf ppf "Unbound value %a.@." Printtyp.longident lid
-
-let dir_untrace_all ppf () =
- List.iter
- (fun f ->
- set_code_pointer f.closure f.actual_code;
- fprintf ppf "%a is no longer traced.@." Printtyp.path f.path)
- !traced_functions;
- traced_functions := []
-
let parse_warnings ppf iserr s =
try Warnings.parse_options iserr s
with Arg.Bad err -> fprintf ppf "%s.@." err
@@ -512,7 +344,7 @@ let trim_signature = function
| mty -> mty
let show_prim to_sig ppf lid =
- let env = !Toploop.toplevel_env in
+ let env = !toplevel_env in
let loc = Location.none in
try
let s =
@@ -697,28 +529,6 @@ let () =
from any of the categories below.";
}
-let _ = add_directive "trace"
- (Directive_ident (dir_trace std_out))
- {
- section = section_trace;
- doc = "All calls to the function \
- named function-name will be traced.";
- }
-
-let _ = add_directive "untrace"
- (Directive_ident (dir_untrace std_out))
- {
- section = section_trace;
- doc = "Stop tracing the given function.";
- }
-
-let _ = add_directive "untrace_all"
- (Directive_none (dir_untrace_all std_out))
- {
- section = section_trace;
- doc = "Stop tracing all functions traced so far.";
- }
-
(* Control the printing of values *)
let _ = add_directive "print_depth"
@@ -784,17 +594,22 @@ let _ = add_directive "warn_error"
let directive_sections () =
let sections = Hashtbl.create 10 in
- let add_dir name dir =
+ let add_dir name =
+ let dir =
+ match get_directive name with
+ | Some dir -> dir
+ | None -> assert false
+ in
let section, doc =
- match Hashtbl.find directive_info_table name with
- | { section; doc } -> section, Some doc
- | exception Not_found -> "Undocumented", None
+ match get_directive_info name with
+ | Some { section; doc } -> section, Some doc
+ | None -> "Undocumented", None
in
Hashtbl.replace sections section
((name, dir, doc)
:: (try Hashtbl.find sections section with Not_found -> []))
in
- Hashtbl.iter add_dir directive_table;
+ List.iter add_dir (all_directive_names ());
let take_section section =
if not (Hashtbl.mem sections section) then (section, [])
else begin
diff --git a/toplevel/topdirs.mli b/toplevel/topdirs.mli
index 77d3660093..a65ae08720 100644
--- a/toplevel/topdirs.mli
+++ b/toplevel/topdirs.mli
@@ -26,12 +26,26 @@ val dir_use : formatter -> string -> unit
val dir_use_output : formatter -> string -> unit
val dir_install_printer : formatter -> Longident.t -> unit
val dir_remove_printer : formatter -> Longident.t -> unit
+
+(* These are now injected from [Topeval], for the bytecode toplevel only:
val dir_trace : formatter -> Longident.t -> unit
val dir_untrace : formatter -> Longident.t -> unit
val dir_untrace_all : formatter -> unit -> unit
+ *)
+
+val section_general : string
+val section_run : string
+val section_env : string
+
+val section_print : string
+val section_trace : string
+val section_options : string
+
+val section_undocumented : string
+
type 'a printer_type_new = Format.formatter -> 'a -> unit
type 'a printer_type_old = 'a -> unit
-(* For topmain.ml. Maybe shouldn't be there *)
-val load_file : formatter -> string -> bool
+(* Here for backwards compatibility, use [Toploop.load_file]. *)
+val[@deprecated] load_file : formatter -> string -> bool
diff --git a/toplevel/topeval.mli b/toplevel/topeval.mli
new file mode 100644
index 0000000000..8d389bce9a
--- /dev/null
+++ b/toplevel/topeval.mli
@@ -0,0 +1,56 @@
+(**************************************************************************)
+(* *)
+(* OCaml *)
+(* *)
+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
+(* *)
+(* Copyright 1996 Institut National de Recherche en Informatique et *)
+(* en Automatique. *)
+(* *)
+(* All rights reserved. This file is distributed under the terms of *)
+(* the GNU Lesser General Public License version 2.1, with the *)
+(* special exception on linking described in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+(** This module provides two alternative implementations for internals of
+ [Toploop], for bytecode and native code.
+
+ You should not use it directly, refer to the functions in [Toploop] instead.
+*)
+
+(**/**)
+
+open Format
+
+(* Accessors for the table of toplevel value bindings. For the bytecode
+ toplevel, these functions must appear as first and second exported functions
+ in this module.
+ (See module Translmod.)
+ They aren't used for the native toplevel.
+*)
+val getvalue : string -> Obj.t
+val setvalue : string -> Obj.t -> unit
+
+val execute_phrase : bool -> formatter -> Parsetree.toplevel_phrase -> bool
+ (* Read and execute commands from a file.
+ [use_file] prints the types and values of the results.
+ [use_silently] does not print them.
+ [mod_use_file] wrap the file contents into a module. *)
+val eval_module_path: Env.t -> Path.t -> Obj.t
+val eval_value_path: Env.t -> Path.t -> Obj.t
+val eval_extension_path: Env.t -> Path.t -> Obj.t
+val eval_class_path: Env.t -> Path.t -> Obj.t
+ (* Return the toplevel object referred to by the given path *)
+
+val eval_address: Env.address -> Obj.t
+ (* Used for printers *)
+
+val may_trace : bool ref
+
+include Topcommon.PRINTER with type Printer.t = Obj.t
+
+(* For topmain.ml. Maybe shouldn't be there *)
+val load_file : bool -> formatter -> string -> bool
+
+val init: unit -> unit
diff --git a/toplevel/toploop.ml b/toplevel/toploop.ml
new file mode 100644
index 0000000000..de456d5aa9
--- /dev/null
+++ b/toplevel/toploop.ml
@@ -0,0 +1,202 @@
+(**************************************************************************)
+(* *)
+(* OCaml *)
+(* *)
+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
+(* *)
+(* Copyright 1996 Institut National de Recherche en Informatique et *)
+(* en Automatique. *)
+(* *)
+(* All rights reserved. This file is distributed under the terms of *)
+(* the GNU Lesser General Public License version 2.1, with the *)
+(* special exception on linking described in the file LICENSE. *)
+(* *)
+(**************************************************************************)
+
+open Format
+include Topcommon
+include Topeval
+
+(* Read and execute commands from a file, or from stdin if [name] is "". *)
+
+let use_print_results = ref true
+
+let use_channel ppf ~wrap_in_module ic name filename =
+ let lb = Lexing.from_channel ic in
+ Warnings.reset_fatal ();
+ Location.init lb filename;
+ (* Skip initial #! line if any *)
+ Lexer.skip_hash_bang lb;
+ Misc.protect_refs
+ [ R (Location.input_name, filename);
+ R (Location.input_lexbuf, Some lb); ]
+ (fun () ->
+ try
+ List.iter
+ (fun ph ->
+ let ph = preprocess_phrase ppf ph in
+ if not (execute_phrase !use_print_results ppf ph) then raise Exit)
+ (if wrap_in_module then
+ parse_mod_use_file name lb
+ else
+ !parse_use_file lb);
+ true
+ with
+ | Exit -> false
+ | Sys.Break -> fprintf ppf "Interrupted.@."; false
+ | x -> Location.report_exception ppf x; false)
+
+let use_output ppf command =
+ let fn = Filename.temp_file "ocaml" "_toploop.ml" in
+ Misc.try_finally ~always:(fun () ->
+ try Sys.remove fn with Sys_error _ -> ())
+ (fun () ->
+ match
+ Printf.ksprintf Sys.command "%s > %s"
+ command
+ (Filename.quote fn)
+ with
+ | 0 ->
+ let ic = open_in_bin fn in
+ Misc.try_finally ~always:(fun () -> close_in ic)
+ (fun () ->
+ use_channel ppf ~wrap_in_module:false ic "" "(command-output)")
+ | n ->
+ fprintf ppf "Command exited with code %d.@." n;
+ false)
+
+let use_file ppf ~wrap_in_module name =
+ match name with
+ | "" ->
+ use_channel ppf ~wrap_in_module stdin name "(stdin)"
+ | _ ->
+ match Load_path.find name with
+ | filename ->
+ let ic = open_in_bin filename in
+ Misc.try_finally ~always:(fun () -> close_in ic)
+ (fun () -> use_channel ppf ~wrap_in_module ic name filename)
+ | exception Not_found ->
+ fprintf ppf "Cannot find file %s.@." name;
+ false
+
+let mod_use_file ppf name =
+ use_file ppf ~wrap_in_module:true name
+let use_file ppf name =
+ use_file ppf ~wrap_in_module:false name
+
+let use_silently ppf name =
+ Misc.protect_refs
+ [ R (use_print_results, false) ]
+ (fun () -> use_file ppf name)
+
+let load_file = load_file false
+
+(* Execute a script. If [name] is "", read the script from stdin. *)
+
+let run_script ppf name args =
+ override_sys_argv args;
+ Compmisc.init_path ~dir:(Filename.dirname name) ();
+ (* Note: would use [Filename.abspath] here, if we had it. *)
+ begin
+ try toplevel_env := Compmisc.initial_env()
+ with Env.Error _ | Typetexp.Error _ as exn ->
+ Location.report_exception ppf exn; raise (Compenv.Exit_with_status 2)
+ end;
+ Sys.interactive := false;
+ run_hooks After_setup;
+ let explicit_name =
+ (* Prevent use_silently from searching in the path. *)
+ if name <> "" && Filename.is_implicit name
+ then Filename.concat Filename.current_dir_name name
+ else name
+ in
+ use_silently ppf explicit_name
+
+(* Toplevel initialization. Performed here instead of at the
+ beginning of loop() so that user code linked in with ocamlmktop
+ can call directives from Topdirs. *)
+let _ =
+ if !Sys.interactive then (* PR#6108 *)
+ invalid_arg "The ocamltoplevel.cma library from compiler-libs \
+ cannot be loaded inside the OCaml toplevel";
+ Sys.interactive := true;
+ Topeval.init ()
+
+let find_ocamlinit () =
+ let ocamlinit = ".ocamlinit" in
+ if Sys.file_exists ocamlinit then Some ocamlinit else
+ let getenv var = match Sys.getenv var with
+ | exception Not_found -> None | "" -> None | v -> Some v
+ in
+ let exists_in_dir dir file = match dir with
+ | None -> None
+ | Some dir ->
+ let file = Filename.concat dir file in
+ if Sys.file_exists file then Some file else None
+ in
+ let home_dir () = getenv "HOME" in
+ let config_dir () =
+ if Sys.win32 then None else
+ match getenv "XDG_CONFIG_HOME" with
+ | Some _ as v -> v
+ | None ->
+ match home_dir () with
+ | None -> None
+ | Some dir -> Some (Filename.concat dir ".config")
+ in
+ let init_ml = Filename.concat "ocaml" "init.ml" in
+ match exists_in_dir (config_dir ()) init_ml with
+ | Some _ as v -> v
+ | None -> exists_in_dir (home_dir ()) ocamlinit
+
+let load_ocamlinit ppf =
+ if !Clflags.noinit then ()
+ else match !Clflags.init_file with
+ | Some f -> if Sys.file_exists f then ignore (use_silently ppf f)
+ else fprintf ppf "Init file not found: \"%s\".@." f
+ | None ->
+ match find_ocamlinit () with
+ | None -> ()
+ | Some file -> ignore (use_silently ppf file)
+
+(* The interactive loop *)
+
+exception PPerror
+
+let loop ppf =
+ Clflags.debug := true;
+ Location.formatter_for_warnings := ppf;
+ if not !Clflags.noversion then
+ fprintf ppf " OCaml version %s@.@." Config.version;
+ begin
+ try initialize_toplevel_env ()
+ with Env.Error _ | Typetexp.Error _ as exn ->
+ Location.report_exception ppf exn; raise (Compenv.Exit_with_status 2)
+ end;
+ let lb = Lexing.from_function refill_lexbuf in
+ Location.init lb "//toplevel//";
+ Location.input_name := "//toplevel//";
+ Location.input_lexbuf := Some lb;
+ Location.input_phrase_buffer := Some phrase_buffer;
+ Sys.catch_break true;
+ run_hooks After_setup;
+ load_ocamlinit ppf;
+ while true do
+ let snap = Btype.snapshot () in
+ try
+ Lexing.flush_input lb;
+ (* Reset the phrase buffer when we flush the lexing buffer. *)
+ Buffer.reset phrase_buffer;
+ Location.reset();
+ Warnings.reset_fatal ();
+ first_line := true;
+ let phr = try !parse_toplevel_phrase lb with Exit -> raise PPerror in
+ let phr = preprocess_phrase ppf phr in
+ Env.reset_cache_toplevel ();
+ ignore(execute_phrase true ppf phr)
+ with
+ | End_of_file -> raise (Compenv.Exit_with_status 0)
+ | Sys.Break -> fprintf ppf "Interrupted.@."; Btype.backtrack snap
+ | PPerror -> ()
+ | x -> Location.report_exception ppf x; Btype.backtrack snap
+ done
diff --git a/toplevel/toploop.mli b/toplevel/toploop.mli
index 45a43bc3f6..ea18fc28db 100644
--- a/toplevel/toploop.mli
+++ b/toplevel/toploop.mli
@@ -53,11 +53,19 @@ val add_directive : string -> directive_fun -> directive_info -> unit
@since 4.03 *)
-val directive_table : (string, directive_fun) Hashtbl.t
- (* Deprecated: please use [add_directive] instead of inserting
+val get_directive : string -> directive_fun option
+
+val get_directive_info : string -> directive_info option
+
+val all_directive_names : unit -> string list
+
+val[@deprecated] directive_table : (string, directive_fun) Hashtbl.t
+ (* @deprecated please use [add_directive] instead of inserting
in this table directly. *)
-val directive_info_table : (string, directive_info) Hashtbl.t
+val[@deprecated] directive_info_table : (string, directive_info) Hashtbl.t
+ (* @deprecated please use [add_directive] instead of inserting
+ in this table directly. *)
val toplevel_env : Env.t ref
(* Typing environment for the toplevel *)
@@ -89,6 +97,8 @@ val eval_class_path: Env.t -> Path.t -> Obj.t
(* Return the toplevel object referred to by the given path *)
val record_backtrace : unit -> unit
+val load_file: formatter -> string -> bool
+
(* Printing of values *)
val print_value: Env.t -> Obj.t -> formatter -> Types.type_expr -> unit