Skip to content

Commit

Permalink
Merge pull request #15 from whitequark/rewriter
Browse files Browse the repository at this point in the history
Add rewriter debugging tool
  • Loading branch information
alainfrisch committed Sep 29, 2014
2 parents 158b339 + 439dbed commit e6c1f0f
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 17 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
dumpast
genlifter
ppx_metaquot
rewriter
ast_lifter.ml
9 changes: 6 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ OCAMLOPT = ocamlopt
COMPFLAGS = -w +A-4-17-44-45 -I +compiler-libs -safe-string

.PHONY: all
all: genlifter$(EXE) dumpast$(EXE) ppx_metaquot$(EXE) ast_mapper_class.cmo ppx_tools.cma
all: genlifter$(EXE) dumpast$(EXE) ppx_metaquot$(EXE) rewriter$(EXE) ast_mapper_class.cmo ppx_tools.cma
all: ppx_tools.cmxa ppx_tools.cmxs

genlifter$(EXE): ppx_tools.cma genlifter.cmo
Expand All @@ -22,10 +22,12 @@ genlifter$(EXE): ppx_tools.cma genlifter.cmo
dumpast$(EXE): dumpast.cmo
$(OCAMLC) $(COMPFLAGS) -o dumpast$(EXE) ocamlcommon.cma ocamlbytecomp.cma ast_lifter.cmo dumpast.cmo


ppx_metaquot$(EXE): ppx_metaquot.cmo
$(OCAMLC) $(COMPFLAGS) -o ppx_metaquot$(EXE) ocamlcommon.cma ppx_tools.cma ast_lifter.cmo ppx_metaquot.cmo

rewriter$(EXE): rewriter.cmo
$(OCAMLC) $(COMPFLAGS) -o rewriter$(EXE) ocamlcommon.cma rewriter.cmo

ast_lifter.ml: genlifter$(EXE)
./genlifter$(EXE) -I +compiler-libs Parsetree.expression > ast_lifter.ml || rm -rf ast_lifter.ml

Expand Down Expand Up @@ -70,7 +72,7 @@ clean:
# Install/uninstall

INSTALL = META \
genlifter$(EXE) dumpast$(EXE) ppx_metaquot$(EXE) \
genlifter$(EXE) dumpast$(EXE) ppx_metaquot$(EXE) rewriter$(EXE) \
ppx_tools.cma ppx_tools.cmxa ppx_tools$(EXT_LIB) \
ppx_tools.cmxs \
ast_convenience.cmi ast_convenience.cmx \
Expand All @@ -92,6 +94,7 @@ DISTRIB = \
dumpast.ml \
genlifter.ml \
ppx_metaquot.ml \
rewriter.ml \
ast_mapper_class.ml ast_mapper_class.mli

FPACKAGE = $(PACKAGE)-$(VERSION)
Expand Down
43 changes: 29 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,35 @@ Executables are thus accessible through the ocamlfind driver (e.g.:
ocamlfind ppx_tools/dumpast).


ppx_metaquot
------------

A ppx filter to help writing programs which manipulate the Parsetree,
by allowing the programmer to use concrete syntax for expressions
creating Parsetree fragments and patterns deconstructing Parsetree
fragments. See the top of ppx_metaquot.ml for a description of the
supported extensions.

Usage:

ocamlfind -c -package ppx_tools.metaquot my_ppx_code.ml


rewriter
--------

An utility to help testing ppx rewriters that runs the rewriter on
user-provided code and returns the result.

Usage:

ocamlfind ppx_tools/rewriter ./my_ppx_rewriter sample.ml

See the integrated help message for more details:

ocamlfind ppx_tools/rewriter -help


Ast_mapper_class
----------------

Expand Down Expand Up @@ -45,20 +74,6 @@ whole files. The tool has further option to control how location and
attribute fields in the Parsetree should be displayed.


ppx_metaquot
------------

A ppx filter to help writing programs which manipulate the Parsetree,
by allowing the programmer to use concrete syntax for expressions
creating Parsetree fragments and patterns deconstructing Parsetree
fragments. See the top of ppx_metaquot.ml for a description of the
supported extensions.

Usage:

ocamlfind -c -package ppx_tools.metaquot my_ppx_code.ml


genlifter
---------

Expand Down
105 changes: 105 additions & 0 deletions rewriter.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
(* This file is part of the ppx_tools package. It is released *)
(* under the terms of the MIT license (see LICENSE file). *)
(* Copyright 2014 Peter Zotov *)

let inputs : ([ `Struct | `Sig ] * [ `String | `Path ] * string) list ref = ref []
let output_file : string ref = ref "-"
let tool_name = ref "ocamlc"

let args =
let open Arg in
align [
"-ppx", String (fun s -> Clflags.all_ppx := s :: !Clflags.all_ppx),
"<cmd> Invoke <cmd> as a ppx preprocessor";

"-str", String (fun s -> inputs := (`Struct, `String, s) :: !inputs),
"<str> Parse <str> as a structure";

"-sig", String (fun s -> inputs := (`Sig, `String, s) :: !inputs),
"<str> Parse <str> as a signature";

"-impl", String (fun s -> inputs := (`Struct, `Path, s) :: !inputs),
"<file> Parse <file> as an implementation (specify - for stdin)";

"-intf", String (fun s -> inputs := (`Sig, `Path, s) :: !inputs),
"<file> Parse <file> as an interface (specify - for stdin)";

"-o", Set_string output_file,
"<file> Write result into <file> (stdout by default)";

"-tool-name", Set_string tool_name,
"<str> Set tool name to <str> (ocamlc by default)";

"-I", String (fun s -> Clflags.include_dirs := s :: !Clflags.include_dirs),
"<dir> Add <dir> to the list of include directories";

"-open", String (fun s -> Clflags.open_modules := s :: !Clflags.open_modules),
"<module> Add <module> to the list of opened modules";

"-for-pack", String (fun s -> Clflags.for_package := Some s),
"<ident> Preprocess code as if it will be packed inside <ident>";

"-g", Set Clflags.debug,
" Request debug information from preprocessor";
]

let anon_arg s =
match !Clflags.all_ppx with
| [] -> Clflags.all_ppx := s :: !Clflags.all_ppx
| _ -> inputs := (`Struct, `Path, s) :: !inputs

let usage_msg =
Printf.sprintf
"Usage: %s [ppx-rewriter] [options...] [implementations...]\n\
If no implementations are specified, parses stdin."
Sys.argv.(0)

let wrap_open fn file =
try fn file
with Sys_error msg ->
prerr_endline msg;
exit 1

let make_lexer source_kind source =
match source_kind, source with
| `String, _ ->
Location.input_name := "//toplevel//";
Lexing.from_string source
| `Path, "-" ->
Location.input_name := "//toplevel//";
Lexing.from_channel stdin
| `Path, _ ->
Location.input_name := source;
Lexing.from_channel (wrap_open open_in source)

let () =
Arg.parse args anon_arg usage_msg;
if !Clflags.all_ppx = [] then begin
Arg.usage args usage_msg;
exit 1
end;
if !inputs = [] then
inputs := [`Struct, `Path, "-"];
let fmt =
match !output_file with
| "-" -> Format.std_formatter
| file -> Format.formatter_of_out_channel (wrap_open open_out file)
in
try
!inputs |> List.iter (fun (ast_kind, source_kind, source) ->
let lexer = make_lexer source_kind source in
match ast_kind with
| `Struct ->
let pstr = Parse.implementation lexer in
let pstr = Pparse.apply_rewriters (* ~restore:true *) ~tool_name:!tool_name
Config.ast_impl_magic_number pstr in
Pprintast.structure fmt pstr;
Format.pp_print_newline fmt ()
| `Sig ->
let psig = Parse.interface lexer in
let psig = Pparse.apply_rewriters (* ~restore:true *) ~tool_name:!tool_name
Config.ast_intf_magic_number psig in
Pprintast.signature fmt psig;
Format.pp_print_newline fmt ())
with exn ->
Location.report_exception Format.err_formatter exn

0 comments on commit e6c1f0f

Please sign in to comment.