ocaml-ppx / ppxlib Goto Github PK
View Code? Open in Web Editor NEWBase library and tools for ppx rewriters
License: MIT License
Base library and tools for ppx rewriters
License: MIT License
I've been having to maintain a pin of ppxlib that restores the ocamlbuild
plugin, for compatibility with BinaryAnalysisPlatform/bap#820. Since the changes consist literally of nothing but reverting the deletion of files in the ocamlbuild_plugin/
directory, I would like to request that this support be restored. I can make a PR easily.
Otherwise, we will need to vendor a separate version of ppxlib somewhere, which will be a lot of trouble since we will need to change the name etc. to not conflict with other installations of ppxlib (unless there is some easy way of simply splitting the plugin into a separate, optional package).
Hi, I’m trying to write a PPX extension in which the extension point is used in place of a "case" statement. Usage would look like:
match x with
| 1 -> 1
| [%myExt pattern TO expression]
| _ -> 3
A "case" node produced by Parsetree has the form:
type case = {
| pc_lhs : pattern;
| pc_guard : expression option;
| pc_rhs : expression;
}
When creating an Extension.t, Extension.declare requires a Context.t as an argument. However, there is no Context.t for type "case".
Is there any lower-level way I can register my transformation to the Driver without using declare or do I require official support for a Context.case?
ast_pattern.ml
defines a drop
pattern, which is used to match against any pattern and then discard it without capturing. Consider the following example: say I want to capture and do something to a let .. = ..
declaration. I would make a pstr_value
pattern as follows:
val pstr_value : (rec_flag, 'a, 'b) t -> (value_binding list, 'b, 'c) t -> (structure_item, 'a, 'c) t
pstr_value __ __
Where the first __
captures the recursive/non-recursive flag, and the second __
captures the actual .. = ..
pairs. I would define a continuation to handle the captured values as such:
fun rec_flag bindings ->
bindings
|> List.map ..
But I'm not interested in the rec_flag
at all! I would much rather write
fun bindings ->
bindings
|> List.map ..
rather than have to prepend a _
parameter, or have to change my handling function's signature every time the pattern is changed--for instance, if I have a function that transforms value_binding
s in different contexts, and in some contexts, the pattern capturing the value_binding
comes with an extra parameter, then instead of using the same handler function for both cases, I have to pass one of them through an extra map
first if I want to reuse the same handler. It would be much more convenient if I could write something like
pstr_value drop __
or, if one wants to get creative with symbols,
pstr_value ___ __
so that the value matched by the ___
/drop
is effectively an "any" match without actually capturing the value. It would be somewhat similar to the ptyp_any
pattern, which captures any type expression, but instead something like pany_any
.
I'm currently trying to write a ppx extension that would be rewritten to the fully qualified path of the value it appears in (see https://github.com/NathanReb/ppx_there).
It seems that the right way to do that currently is to use Ppxlib.Driver.register_transformation ~impl:my_expand_function
because I need some context to actually rewrite the extension node.
I looked into Extension
though and found out about Extension.Expert
. I'm not quite sure I got this right but I have the impression that for now the only thing it allows me to do is to verify the payload fits the declared Ast_pattern.t
and if so get the payload node.
I was wondering if there were more helpers for such ppx plugins provided by ppxlib
as I feel like I'm gonna redo a lot of the work that's already done here.
These are only used for [@@deriving ...]
and it's unlikely they'll ever be used for something else. Now that [@@deriving]
is part of ppxlib, I think removing them and specializing the implementation to only support [@@deriving ...]
would make the code simpler.
Recent versions of metaocaml mark quotations and splicing using ppx attributes.
For example .< e >.
is desugared at parsing time in e [@metaocaml.bracket]
.
ppxlib doesn't seem to recognize them, and complain loudly about them being unused. It would be nice to recognize them, and let them pass through to the (modified) typechecker.
I got the issue with ppx_sexp_conv
, but I figured this is the right repository for this.
The other Ast_builder.p*
and Ast_builder.e*
functions, such as estring
and eint
and pvar
, etc., take in "simple" values, making it easier to construct common patterns/expressions without too much verbosity. For instance, to create the string expression "hello"
, we can do
val estring : loc:Location.t -> string -> expression
estring ~loc:Location.none "hello"
significantly simplifies
{ pexp_desc = Pexp_constant (Pconst_string ("hello", None))
; pexp_loc = Location.none
; pexp_loc_stack = []
; pexp_attributes = []
}
as well as the `Ast_builder` direct equivalent
```ocaml
pexp_constant ~loc:Location.none (Pconst_string ("hello", None))
It is very nice.
Meanwhile, we have pconstruct
(resp. econstruct
), which, for some reason, takes in a whole constructor declaration, completely defeating the purpose of having a pconstruct
function. As an example, create a Some x
constructor pattern, the shortest way to call the current pconstruct
function is
val pconstruct : constructor_declaration -> pattern option -> pattern
pconstruct
(constructor_declaration
~name:{ txt = "Some"; loc = Location.none }
~args:[]
~res:None
)
(pvar "x")
In fact, _simply calling the explicit ppat_construct
function is much more concise:
ppat_construct
{ txt = "Some"; loc = Location.none }
(pvar "x")
Here's a few reasons why this current behavior is not good:
It completely defeats the purpose of having a pconstruct
function, since the pconstruct
call is twice as long as the direct AST construction via ppat_construct
!
Bad semantics: the ~args
and ~res
properties of the constructor declaration is irrelevant when constructing the match-pattern--it's simply not the right type to use! The source for Ast_builder
confirms that pconstruct
only uses name
and loc
of the constructor:
let pconstruct cd arg = ppat_construct ~loc:cd.pcd_loc (Located.map_lident cd.pcd_name) arg
hence semantically, it doesn't make sense to take in a whole constructor_declaration
.
Another semantic error here is that constructor-patterns take Longident.t
identifier values, such as Http.Request_kind
, but constructor-declarations are only supposed to take strings without dots, i.e. Request_kind
. One can simply use a string with a .
in it and pass that to constructor_declaration
, but that again is not a good semantic; furthermore, the current implementation does not parse strings the way evar
does, so having strings with .
instead of using Longident.t
actually can break things in certain cases.
It uses inconsistent API conventions. All the other functions in Ast_builder.Default
are called with a leading ~loc
argument to specify the location, but pconstruct
doesn't but instead steals it from the constructor_declaration
implicitly via .pcd_loc
. That not only means sometimes using the incorrect location (if a PPX parses a constructor declaration, stores it, and builds a constructor pattern later, the location referenced should be that of the pattern-matching construct, not the original declaration) but is also just inconsistent API.
The proposal: replace the current interface/implementation with
val pconstruct : loc:Location.t -> string -> pattern option -> pattern
let pconstruct ~loc name arg =
ppat_construct
~loc
{ txt = Longident.parse name; loc }
arg
Which would be used like
(pconstruct "Some" @@ Some (pvar "x"))
Which would be much nicer to use, and matches the other p*
functions. Something similar would be done to econstruct
.
The home page (https://ppxlib.readthedocs.io/en/latest/) links to Index (https://ppxlib.readthedocs.io/en/latest/genindex.html), which has no content, and Module Index (https://ppxlib.readthedocs.io/en/latest/py-modindex.html), which does not exist. I cannot find API documentation on that site. Is this a mistake?
Could a schema for attributes more generic than the attr_
* rules be added to the local rewriting rules, with an API similar to that for extensions? For example the [@JSX]
attributes the Reason parser attaches to expressions it parsed as JSX are supposed to be used to be rewritten by custom ppx, so it would be nice to be able to define a rule to match expression nodes that have that attribute.
If I have a value of type Ppxlib.Deriving.t
, can I extract the pieces used to create it, in particular, the str_type_decl
?
If I can't pull out that piece directly, is there some other way to apply the function embedded in the deriver.
I've looked at the types and documentation, and don't see how to proceed.
ppx_deriving supports an optional flag. From their docs:
It's possible to make deriving ignore a missing plugin rather than raising an error by passing an optional = true option, for example, to enable conditional compilation:
type addr = string * int [@@deriving yojson { optional = true }]
This works well for their builtins, but doesn't seem to work for bin_io - which is making writing platform independent code difficult. The bin_io folks suggested that this would need to be implemented here.
Is this the place to support optional
for all ppx derivers?
To achieve feature parity with ppx_deriving, we should add this feature to ppxlib: ocaml-ppx/ppx_deriving#94
build environment was installed via "opam install ppxlib"
$ ocaml --version
The OCaml toplevel, version 4.10.0
ppxlib-0.12.0 $ dune runtest
expect_test alias test/base/runtest (got signal ABRT)
(cd _build/default && test/expect/expect_test.exe test/base/test.ml &> /dev/null
expect_test alias test/code_path/runtest (got signal ABRT)
(cd _build/default && test/expect/expect_test.exe test/code_path/test.ml &> /dev/null
expect_test alias test/deriving/runtest (got signal ABRT)
(cd _build/default && test/expect/expect_test.exe test/deriving/test.ml &> /dev/null
expect_test alias test/driver/attributes/runtest (got signal ABRT)
(cd _build/default && test/expect/expect_test.exe test/driver/attributes/test.ml &> /dev/null
expect_test alias test/driver/non-compressible-suffix/runtest (got signal ABRT)
(cd _build/default && test/expect/expect_test.exe test/driver/non-compressible-suffix/test.ml &> /dev/null expect_test alias test/driver/transformations/runtest (got signal ABRT)
(cd _build/default && test/expect/expect_test.exe test/driver/transformations/test.ml &> /dev/null
expect_test alias test/quoter/runtest (got signal ABRT)
(cd _build/default && test/expect/expect_test.exe test/quoter/test.ml &> /dev/null
expect_test alias test/traverse/runtest (got signal ABRT)
(cd _build/default && test/expect/expect_test.exe test/traverse/test.ml &> /dev/null
default $ test/expect/expect_test.exe test/base/test.ml
Fatal error: executable program file not found
Aborted
Ocamlformat is the default in Jane Street, but I don't know how people outside Jane Street feel about it.
Would the ppxlib maintainers entertain a pull request that ocamlformat'ed ppxlib?
Currently they don't build
I have a transformation distrib
which generates code suitable for transforming by deriving
. I linked them into executable and -print-transformation
switch gives both distrib
and deriving
.
But when I run compiled executable with two transformations only first one seems to be applied. I tried to use -apply deriving,distrib,deriving,deriving,deriving,distrib
but only distrib
is being applied. I tried to use standalone rewriter executable for my deriving
plugin using -pp
switch to pass distrib
before running deriving
. It worked as expected: distrib
has generated code with [@@deriving...]
inside and deriving
have expanded everything in the end.
The question is: how exactly multiple rewriters linked together are working? From my current perspective it seems that if we have two transformations then the 2nd one is not applied to the code generated by the first one. Is it intentional?
P.S. I discovered that -no-merge
leads to expected behavior.
Hello, I am trying to write a ppx that essentially just drop-in replaces the expression [%operating_system]
to a string which represents the operating system the user is running on.
In skeleton/pseudocode, this was the idea I was trying to go for:
open Ppxlib
let name = "operating_system"
let expand ~loc ~path:_ (env : string) =
Ast_builder.Default.estring s ~loc
let ext =
Extension.declare
name
Extension.Context.expression
____
expand
let () = Ppxlib.Driver.register_transformation name ~extensions:[ext]
However, I'm not sure what to put where the ____
is if I don't require any arguments to be passed into my expression. Is there a way to do this without using more direct language hooks?
Along with the Longindent.parse
deprecation there is seem to be a fatal error: "OCaml and preprocessor have incompatible versions":
- 14 | let lident x = mk (Longident.parse x)
- ^^^^^^^^^^^^^^^
- Alert deprecated: Longident.parse
- this function may misparse its input,
- use "Parse.longident" or "Longident.unflatten"
- ocamlopt src/gen/.gen_ast_pattern.eobjs/native/import.{cmx,o}
- File "src/gen/import.ml", line 14, characters 21-36:
- 14 | let lident x = mk (Longident.parse x)
- ^^^^^^^^^^^^^^^
- Alert deprecated: Longident.parse
- this function may misparse its input,
- use "Parse.longident" or "Longident.unflatten"
- ocamldep traverse/.ppxlib_traverse.objs/ppxlib_traverse.pp.ml.d (exit 2)
- (cd _build/default && /home/travis/.opam/ocaml-variants.4.11.0+trunk/bin/ocamldep.opt -modules -impl traverse/ppxlib_traverse.pp.ml) > _build/default/traverse/.ppxlib_traverse.objs/ppxlib_traverse.pp.ml.d
- >> Fatal error: OCaml and preprocessor have incompatible versions
- Fatal error: exception Misc.Fatal_error
[ERROR] The compilation of ppxlib failed at
"/home/travis/.opam/opam-init/hooks/sandbox.sh build dune build -p
ppxlib -j 1".
See full log at https://travis-ci.org/github/ocaml-ppx/ppx_deriving/jobs/683869554#L883
Caught in ocaml-ppx/ppx_deriving#220 by @kit-ty-kate
There is a command to build custom rewriter using ocamlfind
but I currently have some troubles making things work
The problem is that current approach relies on the fact that ppx plugin is built as findlib library. And if I'm developing syntax extension in my project and want to run some tests than I need to compile syntax extension and after that compile tests with adjusted OCAMLPATH variable. I tried to pass cmxa
manually and remove dependency on findlib package but it seems that the order of cmxa
's matters and only way to do every all right is to reference PPX package. With this approach there is also an issue with dependencies: tests should be recompiled when the package changes and this currently doesn't work as I want.
Can you give me a piece of advice without recommending switching to dune
?
P.S. This is a question mentioned in #18
#=== ERROR while compiling ppxlib.0.2.1 =======================================#
# context 2.0.0~rc3 | linux/x86_64 | ocaml-system.4.06.0 | file:///home/akochkov/data/tmp/opam-repository
# path ~/.opam/default/.opam-switch/build/ppxlib.0.2.1
# command ~/.opam/default/bin/jbuilder build -p ppxlib -j 7
# exit-code 1
# env-file ~/.opam/log/ppxlib-630120-bf8001.env
# output-file ~/.opam/log/ppxlib-630120-bf8001.out
### output ###
# File "src/jbuild", line 18, characters 17-40:
# Error: "ocaml-migrate-parsetree" is not a ppx driver
<><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
┌─ The following actions failed
│ λ build ppxlib 0.2.1
└─
I want to write [@@deriving foo ~name1:... ~name2:... ~name3:.... ....... ~name100500:....]
where all name%d
should be arbitrary. In the generation function I want to get a (Longident.t loc * expression) list
with all the expressions that describe the arguments of foo
.
Following ocaml/dune#1861 I'm trying to add a specific behaviour when my ppxlib
based deriver is used in an ocamldep
context. ocaml-migrate-parsetree
seems to make it available through a config argument but I can't seem to find how I could access it from ppxlib
.
I worked out an ugly solution to come around that limitation for now but if I'm indeed not missing something, it might be useful to find a way to pass it on to the actual ast -> ast
function.
This sums up a discussion we had with @hhugo this morning. There is no action to take on this ticket, I'm just leaving it here so that the plan is clear and in case others want to chime in.
The API of ppxlib is based on a selected version of the AST. This version is not fixed forever and will move from now and then. It will likely change shortly after every new release of the compiler. This means that projects using ppxlib might break every time the selected version of the AST is updated.
The planned solution is to integrate ppx_view into ppxlib for the 1.0.0 release of ppxlib. With ppx_view, we can provide a stable API to deconstruct the AST. Coupled with a stable API to construct the AST and the various traversal classes provided by ppxlib, this will allow ppx rewriters to replace some or all of their explicit references to the concrete data types of Parsetree
.
Another other solution would be to do like ocaml-migrate-parsetree and ppx_tools and provide several versions of the whole ppxlib library. However, I believe that the cost will be too high in terms of both maintainability and complexity of the overall system.
Hi, I'm trying to write my first ppx rewriter for Ocaml using ppxlib and when I tried to open Ast_mapper I was confronted with the error Accessing this module directly is deprecated, use Ocamlcommon.Ast_mapper instead
, however it took me quite some searching to find that the module is actually called "Ocaml_common". This should be fixed.
(As an aside, a link to the most up-to-date documentation would be greatly appreciated as most of the PPX docs and tutorials are very old and inconsistent :/ )
This ticket describe how to integrate ppx_view in ppxlib. This is the last major work to do before we release the 1.0.0 version of ppxlib. These two projects could stay separate, however given that using view pattern will improve a lot the ppx compatibility story, I believe that it is worth merging them to promote the use of view patterns.
The rest of this PR explains what needs to be done.
ppx_view
is composed of:
ppx_view.lib
, a library defining the type of view patterns + some combinators. It is used as the runtime library of the ppx rewriterppx_view
, a ppx rewriter that interprets match%view ...
expressions and produces code using the ppx_view.lib
libraryppx_view.ast
, a library providing view patterns for the OCaml AST. Its API is the dual of the Ast_helper
module from the compiler librariesA lot of the code of ppx_view.ast
is automatically generated from parsetree.mli.
ppx_view.lib
and ppx_view.ast
can be integrated in ppxlib
as it. Most of the work will be on integrating ppx_view.ast
so that the overall API of ppxlib stays consistent and is ready for long term backward compatibility.
ppxlib
currently has a Ppxlib.Ast_pattern
module that serve a purpose similar to the one of ppx_view.ast
. However, the API of Ppxlib.Ast_pattern
follows the naming convention of Ppxlib.Ast_builder
rather than Ast_helper
.
It doesn't make sense to maintain both Ppxlib.Ast_pattern
and the original ppx_view.ast
. View patterns are better than what Ppxlib.Ast_pattern
currently provides, so we should migrate Ast_pattern
to use plain view patterns instead. However, to make it easier to upgrade code currently using Ppxlib.Ast_pattern
, we should keep the current naming conventions of Ast_pattern
.
Most of the combinators of Ast_pattern
are generated, so it should be easy to adapt the generator to generate view patterns.
As the OCaml AST evolves, we will update the API of Ast_builder
and Ast_pattern
in backward compatible ways. For instance by adding new foo_v409
functions, or by clever use of optional arguments. One consequence is that we can no longer generate the interface of Ast_builder
and Ast_pattern
. Instead, we should just infer the mli of Ast_pattern_generated
and include it in Ast_pattern
and do the same for Ast_builder
. The implementation can still be generated, and we will overload a few functions in Ast_pattern
to make sure to preserve backward compatibility when the signature of the generated functions change.
While this will work fine, over time the API will become quite ugly and we will want to clean it up. For this reason, we should version the whole API of Ast_builder
and Ast_pattern
. I.e. Ast_builder
will become Ast_builder.V1
and Ast_pattern
will become Ast_pattern.V1
. When the API will become too messy, we will mint V2
versions.
Note: to make things simpler, we can get rid of Ast_builder.Make
. This function is almost never used and it is more code to maintain.
Fedora Rawhide currently has a prerelease of OCaml 4.11. Building ppxlib now fails like so:
File "src/gen/import.ml", line 14, characters 21-36:
14 | let lident x = mk (Longident.parse x)
^^^^^^^^^^^^^^^
Error (alert deprecated): Longident.parse
this function may misparse its input,
use "Parse.longident" or "Longident.unflatten"
What is the right thing to do? Should I disable the alert and leave the code as is? Would it be correct to replace (Longident.parse x)
with (Parse.longident (Lexing.from_string x))
?
The current documentation page for ppxlib (March 2019) has two aspects that are worth an issue:
Many of the content seems missing. On my machine the "Index" page is empty and the "Module Index" page appears to show a platform-specific missing-page content.
There are ads now in the left column. (In my case a message about the fact that I have an ad-blocker, but should support them by watching their "Ethical ads".)
The second point is I think worth thinking about. Yes, ReadtheDocs is a cool platform that lowers barrier to entry by being visually appealing and being similar to the documentation of other famous/popular systems, but is it worth showing ads in OCaml project documentations? Maybe you should consider keeping the exact same style but migrating to dedicated hosting space, without the ads. I think this shows that centralizing documentation in one third-party website is often not, in the long run, the best approach.
Currenlty it seems that the location passed to the generator function
loc: Location.t -> path: string -> `input_ast -> `output_ast
at least in the str_type_decl
case is the loc for the whole Pstr_type
node. This is a bit annoying because if you then use that loc
for the generated nodes (which I assume is what most ppxlib
users do) that means that any error in there will be reported on the whole type declaration. That can be a bit confusing to the end user of the deriving plugin.
What I'd like to be able to do instead is locate it on the attribute node for [@@deriving ...]
which I believe would make more sense. It might even be worth locating it on the right part of the attribute payload, ie the one corresponding to the registered deriver.
I don't think there's a nice way, if there's even one, to get that location from the input ast nodes.
Would you consider changing what is passed as loc
or at least adding a separate argument for the different relevant locations?
This is a continuation of https://discuss.ocaml.org/t/semi-optional-deriving-arguments-using-ppxlib/1817
@diml the default
field and the whole type 'a Deriving.Args.param
is not exposed to the mli
. So, I can't do what I want without patching ppxlib
. Am I right?
The function make takes this ?attributes
argument but as far as I can tell doesn't do anything except store it. I've dug into the source and I see some commented source that would remove this attribute, but this is no longer done. Can the purpose of this argument be documented perhaps?
In ppxlib 0.8.0
, the file ast/import.ml
contains the line:
module Js = Migrate_parsetree.OCaml_407
When building in an OCaml 4.08 setup, that seems to make Ppxlib.Parsetree
refer to the Parsetree
in Ast_407
from ocaml-migrate-parsetree
.
That seems wrong, and makes code fail to compile that compiled fine with OCaml 4.07.1.
Shouldn't that line use the current version of OCaml, rather than a fixed version?
I recently ran into this. It's not a major issue and although I know I shouldn't rely too much on the pretty printed ASTs, I do for testing which makes this a bit annoying.
For example, in ppx_yojson
tests I diff the pretty printed post rewriting AST for the following piece of code:
let null : json = [%yojson None]
which, until now, was:
let null : json = `Null
for ocaml 4.04
to 4.07
.
With ppxlib.0.8.0
, it is printed as:
let null = (`Null : json)
for ocaml 4.04 and 4.05 but still printed as above for ocaml 4.06 or higher.
Do you have any idea what lead to that change and if there's a way to fix it? Once again it's nothing major but if it's easy/quick enough I'll gladly take care of it!
I'm also curious how to use the -styler
option of the standalone driver as it could offer me a way to work around that.
Would it be possible to extend the ppx s.t. it would include the
module prefixes into its method names via some kind of mangling
scheme? E.g., type Foo.Bar.baz
goes to foo__bar__baz
instead of to
baz
.
(* This is correct. *)
type direct = Direct of int * string [@@deriving_inline traverse_iter]
let _ = fun (_ : direct) -> ()
class virtual iter =
object (self)
method virtual int : int -> unit
method virtual string : string -> unit
method direct : direct -> unit =
fun x ->
match x with
| Direct (a, b) ->
self#int a;
self#string b
end
[@@@end]
(* This generates incorrect code. *)
type with_module_prefixes = With_module_prefixes of Int.t * String.t
[@@deriving_inline traverse_iter]
let _ = fun (_ : with_module_prefixes) -> ()
class virtual iter =
object (self)
method virtual t : t -> unit
method virtual t : t -> unit
method with_module_prefixes : with_module_prefixes -> unit =
fun x ->
match x with
| With_module_prefixes (a, b) ->
self#t a;
self#t b
end
[@@@end]
(* The workaround is to alias the types so I can refer to them without
module prefixes. *)
type int__t = Int.t
type string__t = String.t
type with_aliases = With_aliases of int__t * string__t
[@@deriving_inline traverse_iter]
let _ = fun (_ : with_aliases) -> ()
class virtual iter =
object (self)
method virtual int__t : int__t -> unit
method virtual string__t : string__t -> unit
method with_aliases : with_aliases -> unit =
fun x ->
match x with
| With_aliases (a, b) ->
self#int__t a;
self#string__t b
end
[@@@end]
Hello everyone,
I have recently started doing my first ppx and I encountered a problem:
My goal was to generate functions for a record which I would keep as an abstract type in the signature of my module.
The structure part was working fine but when doing the signature part, I met one problem:
My type being an abstract one, I could not access my record fields anymore, therefore I could not generate the functions signatures.
This is why I was wondering if there was a solution to allow me to have my record information available for the ppx but remove them with the abstraction of my type right after.
What do you think of it ?
+ C:\cygwin64\home\appveyor\.opam\ocaml-variants.4.07.1+mingw32c\bin\dune.exe "runtest" "-p" "ppxlib" "-j" "2" (CWD=C:/cygwin64/home/appveyor/.opam/ocaml-variants.4.07.1+mingw32c/.opam-switch/build/ppxlib.0.9.0)
- cinaps alias src/runtest (exit 2)
- (cd _build/default/src && .cinaps/cinaps.exe -diff-cmd -)
- Fatal error: exception Sys_error("C:\cygwin64\tmp\cinapsf14ff5.mli: Permission denied")
- cinaps alias src/runtest (exit 2)
- (cd _build/default/src && .cinaps/cinaps.exe -diff-cmd -)
- Fatal error: exception Sys_error("C:\cygwin64\tmp\cinapsf14ff5.mli: Permission denied")
[ERROR] The compilation of ppxlib failed at "C:\\cygwin64\\home\\appveyor\\.opam\\ocaml-variants.4.07.1+mingw32c\\bin\\dune.exe runtest -p ppxlib -j 2".
#=== ERROR while compiling ppxlib.0.9.0 =======================================#
# context 2.0.5 | win32/x86_64 | ocaml-variants.4.07.1+mingw32c | pinned(file://C:/projects/ppxlib)
# path ~/.opam/ocaml-variants.4.07.1+mingw32c/.opam-switch/build/ppxlib.0.9.0
# command C:\cygwin64\home\appveyor\.opam\ocaml-variants.4.07.1+mingw32c\bin\dune.exe runtest -p ppxlib -j 2
# exit-code 1
# env-file ~/.opam/log/ppxlib-992-9b8556.env
# output-file ~/.opam/log/ppxlib-992-9b8556.out
### output ###
# cinaps alias src/runtest (exit 2)
# (cd _build/default/src && .cinaps/cinaps.exe -diff-cmd -)
# Fatal error: exception Sys_error("C:\cygwin64\tmp\cinapsf14ff5.mli: Permission denied")
<><> Error report <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
+- The following actions failed
| - build ppxlib 0.9.0
+-
- No changes have been performed
At the tip of master, [dune runtest] fails. I've appended the output below.
I see that the build is good on TravisCI. Am I doing something wrong?
Here's my shell-file:
cd ~/sda/repos/ppxlib
eval $(opam env)
env
git reset --hard
git status
opam switch
dune installed-libraries
dune printenv
dune build
dune runtest
And here's the output:
Fri 16 Aug 2019 07:00:30 PM EDT
------------------------------------------------------------------------------------------
+ cd /home/dwang/sda/repos/ppxlib
++ opam env
+ eval 'OPAM_SWITCH_PREFIX='\''/usr/local/home/dwang/.opam/default'\'';' export 'OPAM_SWITCH_PREFIX;' 'CAML_LD_LIBRARY_PATH='\''/usr/local/home/dwang/.opam/default/lib/stublibs:/usr/local/home/dwang/.opam/default/lib/ocaml/stublibs:/usr/local/home/dwang/.opam/default/lib/ocaml'\'';' export 'CAML_LD_LIBRARY_PATH;' 'OCAML_TOPLEVEL_PATH='\''/usr/local/home/dwang/.opam/default/lib/toplevel'\'';' export 'OCAML_TOPLEVEL_PATH;' 'MANPATH='\'':/usr/local/home/dwang/.opam/default/man'\'';' export 'MANPATH;' 'PATH='\''/usr/local/home/dwang/.opam/default/bin:/tmp/Jane.shell-file.dwang:/j/office/app/emacs/dev/.sink-2019-08-08_20-17-22.814972/jane-elisp/bin:/home/dwang/bin:/home/dwang/.dispatch/bin:/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/j/office/app/emacs/dev/jane-elisp/bin:/j/office/app/ocp-indent/prod/bin'\'';' export 'PATH;'
++ OPAM_SWITCH_PREFIX=/usr/local/home/dwang/.opam/default
++ export OPAM_SWITCH_PREFIX
++ CAML_LD_LIBRARY_PATH=/usr/local/home/dwang/.opam/default/lib/stublibs:/usr/local/home/dwang/.opam/default/lib/ocaml/stublibs:/usr/local/home/dwang/.opam/default/lib/ocaml
++ export CAML_LD_LIBRARY_PATH
++ OCAML_TOPLEVEL_PATH=/usr/local/home/dwang/.opam/default/lib/toplevel
++ export OCAML_TOPLEVEL_PATH
++ MANPATH=:/usr/local/home/dwang/.opam/default/man
++ export MANPATH
++ PATH=/usr/local/home/dwang/.opam/default/bin:/tmp/Jane.shell-file.dwang:/j/office/app/emacs/dev/.sink-2019-08-08_20-17-22.814972/jane-elisp/bin:/home/dwang/bin:/home/dwang/.dispatch/bin:/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/j/office/app/emacs/dev/jane-elisp/bin:/j/office/app/ocp-indent/prod/bin
++ export PATH
+ env
CAML_LD_LIBRARY_PATH=/usr/local/home/dwang/.opam/default/lib/stublibs:/usr/local/home/dwang/.opam/default/lib/ocaml/stublibs:/usr/local/home/dwang/.opam/default/lib/ocaml
MANPATH=:/usr/local/home/dwang/.opam/default/man
HOSTNAME=igm-qws-u12112c
STABLE_BUILD_INFO=true
SHELL=/bin/bash
TERM=dumb
HISTSIZE=1000
RIPGREP_CONFIG_PATH=/home/dwang/.ripgreprc
KRB5CCNAME_STATIC=FILE:/tmp/krb5cc_dwang_static
DE=gnome
OLDPWD=/home/dwang/bin
OPAM_SWITCH_PREFIX=/usr/local/home/dwang/.opam/default
OPAMROOT=/usr/local/home/dwang/.opam
OCAML_TOPLEVEL_PATH=/usr/local/home/dwang/.opam/default/lib/toplevel
QT_GRAPHICSSYSTEM_CHECKED=1
USER=dwang
LS_COLORS=
BUILD_PROFILE=fast-build
PAGER=cat
INLINE_TEST_IN_PLACE=true
MAIL=/var/spool/mail/dwang
PATH=/usr/local/home/dwang/.opam/default/bin:/tmp/Jane.shell-file.dwang:/j/office/app/emacs/dev/.sink-2019-08-08_20-17-22.814972/jane-elisp/bin:/home/dwang/bin:/home/dwang/.dispatch/bin:/usr/lib64/ccache:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/j/office/app/emacs/dev/jane-elisp/bin:/j/office/app/ocp-indent/prod/bin
SANDBOX_RULES=true
HGUSER=Wang <[email protected]>
LC_COLLATE=C
PWD=/home/dwang/sda/repos/ppxlib
IRON_CONFIG=prod
EDITOR=emacsclient
IRON_USE_CHG=true
LANG=en_US.utf8
X_LIBRARY_INLINING=true
MODULEPATH=/usr/share/Modules/modulefiles:/etc/modulefiles
FEATURE_EXPLORER_FE_EXE=/tmp/dwang-emacs-exe-cache/j/office/app/fe/dev/bin/fe
FEATURE_EXPLORER_LOG_FE=false
LOADEDMODULES=
STACK_ROOT=/usr/local/home/dwang/stack
HISTCONTROL=ignoredups
KRB5CCNAME=FILE:/tmp/krb5cc_dwang_static
SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass
SHARED_CACHE=true
CATALOG_BROWSER_BETA=1
HOME=/home/dwang
SHLVL=3
clones=/usr/local/home/dwang/
FE_CRS_SHOULD_UPDATE=true
LESS=-RXM
TMP=/tmp/dwang
LOGNAME=dwang
VISUAL=emacsclient
XDG_DATA_DIRS=/home/dwang/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
PLUGD_INSTANCE=prod
MODULESHOME=/usr/share/Modules
LESSOPEN=||/usr/bin/lesspipe.sh %s
dst=nyc-qws-041
INFOPATH=/home/dwang/usr/local/share/info:
DISPLAY=localhost:15.0
OCAMLRUNPARAM=b=1
BASH_FUNC_undo-rebase()=() { local f=$1;
local new_base=$(fe show -base $f);
local new_tip=$(fe show -tip $f);
local merge=$(hg log -r "limit(reverse(only($new_tip,$new_base) and merge()),1)" -T "{node}\n");
local old_tip=$(hg log -r "$merge" -T "{p1node}\n{p2node}\n" | grep -v "$new_base");
local old_base0=$(hg log -r "$merge" -T "{desc}" | sed -rn 's/^.*rebase to .* with ancestor ([a-f0-9]*)$/\1/p');
local old_base=$(echo "$old_base0" | sed -rn 's/^.*\[([0-9a-f]+)\]$/\1/p');
if [[ -z "$old_base" ]]; then
old_base="$old_base0";
fi;
hg book -f -r "$old_tip" "$f";
hg push -B "$f";
fe change -set-base "$old_base" "$f";
fe tools wait "$f"
}
BASH_FUNC_module()=() { eval `/usr/bin/modulecmd bash $*`
}
_=/usr/bin/env
+ git reset --hard
HEAD is now at 95ca88a Merge pull request #85 from ocaml-ppx/opam-file-fixes
+ git status
On branch print-diff-default-config
nothing to commit, working tree clean
+ opam switch
# switch compiler description
-> default ocaml-base-compiler.4.07.1 default
+ dune installed-libraries
base (version: v0.12.0)
base.caml (version: v0.12.0)
base.md5 (version: v0.12.0)
base.shadow_stdlib (version: v0.12.0)
bigarray (version: [distributed with Ocaml])
bytes (version: [distributed with Ocaml])
compiler-libs (version: [distributed with Ocaml])
compiler-libs.bytecomp (version: [distributed with Ocaml])
compiler-libs.common (version: [distributed with Ocaml])
compiler-libs.optcomp (version: [distributed with Ocaml])
compiler-libs.toplevel (version: [distributed with Ocaml])
dune._caml (version: 1.11.1)
dune._dune_lang (version: 1.11.1)
dune._ocaml_config (version: 1.11.1)
dune._result (version: 1.11.1)
dune._stdune (version: 1.11.1)
dune._wp (version: 1.11.1)
dune._wp.dune (version: 1.11.1)
dune._wp.jbuilder (version: 1.11.1)
dune.configurator (version: 1.11.1)
dynlink (version: [distributed with Ocaml])
ocaml-compiler-libs.bytecomp (version: n/a)
ocaml-compiler-libs.common (version: n/a)
ocaml-compiler-libs.shadow (version: n/a)
ocaml-compiler-libs.toplevel (version: n/a)
ocaml-migrate-parsetree (version: 1.4.0)
ocaml-migrate-parsetree.driver-main (version: 1.4.0)
ppx_derivers (version: n/a)
ppxlib (version: 0.5.0)
ppxlib.ast (version: 0.5.0)
ppxlib.metaquot (version: 0.5.0)
ppxlib.metaquot_lifters (version: 0.5.0)
ppxlib.print_diff (version: 0.5.0)
ppxlib.runner (version: 0.5.0)
ppxlib.runner_as_ppx (version: 0.5.0)
ppxlib.traverse (version: 0.5.0)
ppxlib.traverse_builtins (version: 0.5.0)
re (version: 1.9.0)
re.emacs (version: 1.9.0)
re.glob (version: 1.9.0)
re.pcre (version: 1.9.0)
re.perl (version: 1.9.0)
re.posix (version: 1.9.0)
re.str (version: 1.9.0)
result (version: n/a)
seq (version: [distributed with OCaml 4.07 or above])
sexplib0 (version: v0.12.0)
stdio (version: v0.12.0)
str (version: [distributed with Ocaml])
threads (version: [distributed with Ocaml])
threads.posix (version: [distributed with Ocaml])
threads.vm (version: [distributed with Ocaml])
uchar (version: [distributed with Ocaml])
unix (version: [distributed with Ocaml])
+ dune printenv
((flags
(-w @[email protected]@30..39@[email protected]@[email protected] -strict-sequence
-strict-formats -short-paths -keep-locs -w -66))
(ocamlc_flags (-g))
(ocamlopt_flags (-g))
(c_flags
(-std=gnu99 -O2 -fno-strict-aliasing -fwrapv -fno-builtin-memcmp -fPIC))
(cxx_flags
(-O2 -fno-strict-aliasing -fwrapv -fno-builtin-memcmp -fPIC)))
+ dune build
+ dune runtest
patdiff (internal) (exit 1)
(cd _build/default && /usr/bin/patdiff -keep-whitespace -location-style omake -ascii test/code_path/test.ml test/code_path/test.ml.corrected)
-test/code_path/test.ml
+test/code_path/test.ml.corrected
File "test/code_path/test.ml", line 19, characters 0-1:
open Ppxlib
let () =
Driver.register_transformation "test"
~extensions:[
Extension.V3.declare "code_path"
Expression
Ast_pattern.(pstr nil)
(fun ~ctxt ->
let loc = Expansion_context.Extension.extension_point_loc ctxt in
let code_path = Expansion_context.Extension.code_path ctxt in
Ast_builder.Default.estring ~loc
(Code_path.fully_qualified_path code_path))
]
[%%expect{|
+Unknown directive `require'.
+Line _, characters 16-385:
+Error: This expression has type 'a list
+ but an expression was expected of type
+ Extension.t Ppxlib__Import.sexp_list
|}]
let s =
let module A = struct
module A' = struct
let a =
let module B = struct
module B' = struct
let b =
let module C = struct
module C' = struct
let c = [%code_path]
end
end
in C.C'.c
end
end
in B.B'.b
end
end
in A.A'.a
;;
[%%expect{|
-val s : string = "Test.s"
+Line _, characters 28-37:
+Error: Uninterpreted extension 'code_path'.
|}]
let module M = struct
let m = [%code_path]
end
in
M.m
[%%expect{|
-- : string = "Test"
+Line _, characters 12-21:
+Error: Uninterpreted extension 'code_path'.
|}]
patdiff (internal) (exit 1)
(cd _build/default && /usr/bin/patdiff -keep-whitespace -location-style omake -ascii test/driver/non-compressible-suffix/test.ml test/driver/non-compressible-suffix/test.ml.corrected)
-test/driver/non-compressible-suffix/test.ml
+test/driver/non-compressible-suffix/test.ml.corrected
File "test/driver/non-compressible-suffix/test.ml", line 22, characters 0-1:
open Ast_builder.Default;;
Driver.register_transformation "blah"
~rules:[ Context_free.Rule.extension
(Extension.declare "foo"
Expression
Ast_pattern.(pstr nil)
(fun ~loc ~path:_ -> eint ~loc 42))
; Context_free.Rule.extension
(Extension.declare "@foo.bar"
Expression
Ast_pattern.(pstr nil)
(fun ~loc ~path:_ -> eint ~loc 42))
]
;;
[%%expect{|
-- : unit = ()
+Unknown directive `require'.
+Unknown directive `require'.
+Line _, characters 9-405:
+Error: This expression has type 'a list
+ but an expression was expected of type
+ Context_free.Rule.t Ppxlib__Import.sexp_list
|}]
[%foo];;
[%%expect{|
-- : int = 42
+Line _, characters 2-5:
+Error: Uninterpreted extension 'foo'.
|}]
[%foo.bar];;
[%%expect{|
-- : int = 42
+Line _, characters 2-9:
+Error: Uninterpreted extension 'foo.bar'.
|}]
[%bar];;
[%%expect{|
Line _, characters 2-5:
Error: Uninterpreted extension 'bar'.
|}]
patdiff (internal) (exit 1)
(cd _build/default && /usr/bin/patdiff -keep-whitespace -location-style omake -ascii test/deriving/test.ml test/deriving/test.ml.corrected)
-test/deriving/test.ml
+test/deriving/test.ml.corrected
File "test/deriving/test.ml", line 14, characters 0-1:
#use "topfind";;
#require "base";;
#load "ppxlib_metaquot_lifters.cmo";;
#load "ppxlib_metaquot.cmo";;
open Ppxlib
let foo =
Deriving.add "foo"
~str_type_decl:(Deriving.Generator.make_noarg
(fun ~loc ~path:_ _ -> [%str let x = 42]))
[%%expect{|
-val foo : Deriving.t = <abstr>
+Unknown directive `require'.
+Line _, characters 15-20:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let bar =
Deriving.add "bar"
~str_type_decl:(Deriving.Generator.make_noarg
~deps:[foo]
(fun ~loc ~path:_ _ -> [%str let () = Printf.printf "x = %d\n" x]))
[%%expect{|
-val bar : Deriving.t = <abstr>
+Line _, characters 28-33:
+Error: This expression has type 'a list
+ but an expression was expected of type
+ Deriving.t Ppxlib__Import.sexp_list
|}]
type t = int [@@deriving bar]
[%%expect{|
Line _, characters 25-28:
-Error: Deriver foo is needed for bar, you need to add it before in the list
+Error: Ppxlib.Deriving: 'bar' is not a supported type deriving generator
|}]
type t = int [@@deriving bar, foo]
[%%expect{|
Line _, characters 25-33:
-Error: Deriver foo is needed for bar, you need to add it before in the list
+Error: Ppxlib.Deriving: 'bar' is not a supported type deriving generator
|}]
type nonrec int = int [@@deriving foo, bar]
[%%expect{|
-type nonrec int = int
-val x : int = 42
+Line _, characters 34-42:
+Error: Ppxlib.Deriving: 'foo' is not a supported type deriving generator
|}]
patdiff (internal) (exit 1)
(cd _build/default && /usr/bin/patdiff -keep-whitespace -location-style omake -ascii test/base/test.ml test/base/test.ml.corrected)
-test/base/test.ml
+test/base/test.ml.corrected
File "test/base/test.ml", line 11, characters 0-1:
#use "topfind";;
#require "base";;
#require "stdio";;
open Base
open Stdio
open Ppxlib
module N = Ppxlib_private.Name
[%%expect{|
+Unknown directive `require'.
+Unknown directive `require'.
+Line _, characters 5-9:
+Error: Unbound module Base
+Line _, characters 5-10:
+Error: Unbound module Stdio
+Hint: Did you mean Stdlib?
module N = Ppxlib.Ppxlib_private.Name
|}]
let dot_suffixes name =
Caml.Printf.sprintf "%s"
(Sexp.to_string_hum
(List.sexp_of_t String.sexp_of_t (N.dot_suffixes name)))
[%%expect{|
-val dot_suffixes : string -> string = <fun>
+Line _, characters 2-21:
+Error: Unbound module Caml
|}]
let _ = dot_suffixes "foo.bar.baz"
[%%expect{|
-- : string = "(baz bar.baz foo.bar.baz)"
+Line _, characters 8-20:
+Error: Unbound value dot_suffixes
|}]
let _ = dot_suffixes "[email protected]"
[%%expect{|
-- : string = "(bar.baz foo.bar.baz)"
+Line _, characters 8-20:
+Error: Unbound value dot_suffixes
|}]
let split_path name =
let a, b = N.split_path name in
Caml.Printf.sprintf "%s"
(Sexp.to_string_hum
(List [sexp_of_string a; Option.sexp_of_t sexp_of_string b]))
[%%expect{|
-val split_path : string -> string = <fun>
+Line _, characters 4-23:
+Error: Unbound module Caml
|}]
let _ = split_path "a.b.c"
[%%expect{|
-- : string = "(a.b.c ())"
+Line _, characters 8-18:
+Error: Unbound value split_path
|}]
let _ = split_path "a.b.c.D"
[%%expect{|
-- : string = "(a.b.c (D))"
+Line _, characters 8-18:
+Error: Unbound value split_path
|}]
let _ = split_path ".D"
[%%expect{|
-- : string = "(\"\" (D))"
+Line _, characters 8-18:
+Error: Unbound value split_path
|}]
let convert_longident string =
let lident = Longident.parse string in
let name = Longident.name lident in
(name, lident)
[%%expect{|
-val convert_longident : string -> string * longident = <fun>
+val convert_longident :
+ Ppxlib__Import.string -> Ppxlib__Import.string * longident = <fun>
|}]
let _ = convert_longident "x"
[%%expect{|
-- : string * longident = ("x", Ppxlib.Longident.Lident "x")
+Line _, characters 26-29:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let _ = convert_longident "(+)"
[%%expect{|
-- : string * longident = ("( + )", Ppxlib.Longident.Lident "+")
+Line _, characters 26-31:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let _ = convert_longident "( + )"
[%%expect{|
-- : string * longident = ("( + )", Ppxlib.Longident.Lident "+")
+Line _, characters 26-33:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let _ = convert_longident "Base.x"
[%%expect{|
-- : string * longident =
-("Base.x", Ppxlib.Longident.Ldot (Ppxlib.Longident.Lident "Base", "x"))
+Line _, characters 26-34:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let _ = convert_longident "Base.(+)"
[%%expect{|
-- : string * longident =
-("Base.( + )", Ppxlib.Longident.Ldot (Ppxlib.Longident.Lident "Base", "+"))
+Line _, characters 26-36:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let _ = convert_longident "Base.( + )"
[%%expect{|
-- : string * longident =
-("Base.( + )", Ppxlib.Longident.Ldot (Ppxlib.Longident.Lident "Base", "+"))
+Line _, characters 26-38:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let _ = convert_longident "Base.( land )"
[%%expect{|
-- : string * longident =
-("Base.( land )",
- Ppxlib.Longident.Ldot (Ppxlib.Longident.Lident "Base", "land"))
+Line _, characters 26-41:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let _ = Ppxlib.Code_path.(file_path @@ top_level ~file_path:"dir/main.ml")
[%%expect{|
-- : string = "dir/main.ml"
+Line _, characters 60-73:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let _ = Ppxlib.Code_path.(fully_qualified_path @@ top_level ~file_path:"dir/main.ml")
[%%expect{|
-- : string = "Main"
+Line _, characters 71-84:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let complex_path =
let open Ppxlib.Code_path in
let loc = Ppxlib.Location.none in
top_level ~file_path:"dir/main.ml"
|> enter_module ~loc "Sub"
|> enter_module ~loc "Sub_sub"
|> enter_value ~loc "some_val"
[%%expect{|
-val complex_path : Code_path.t = <abstr>
+Line _, characters 23-36:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
let _ = Ppxlib.Code_path.fully_qualified_path complex_path
[%%expect{|
-- : string = "Main.Sub.Sub_sub.some_val"
+Line _, characters 46-58:
+Error: Unbound value complex_path
|}]
let _ = Ppxlib.Code_path.to_string_path complex_path
[%%expect{|
-- : string = "dir/main.ml.Sub.Sub_sub"
+Line _, characters 40-52:
+Error: Unbound value complex_path
|}]
patdiff (internal) (exit 1)
(cd _build/default && /usr/bin/patdiff -keep-whitespace -location-style omake -ascii test/driver/transformations/test.ml test/driver/transformations/test.ml.corrected)
-test/driver/transformations/test.ml
+test/driver/transformations/test.ml.corrected
File "test/driver/transformations/test.ml", line 32, characters 0-1:
match td.ptype_kind with
| Ptype_record lds ->
if Poly.(<>)
(List.sort lds ~compare:(fun a b -> String.compare a.pld_name.txt b.pld_name.txt))
lds
then
Driver.Lint_error.of_string td.ptype_loc
"Fields are not sorted!"
:: acc
else
acc
| _ -> acc
end
let () =
Driver.register_transformation "lint" ~lint_impl:(fun st -> lint#structure st [])
[%%expect{|
-val lint : Driver.Lint_error.t list Ast_traverse.fold = <obj>
+Unknown directive `require'.
+Unknown directive `require'.
+Line _, characters 5-9:
+Error: Unbound module Base
+Line _, characters 9-18:
+Error: Unbound module Poly
+Line _, characters 62-66:
+Error: Unbound value lint
|}]
type t =
{ b : int
; a : int
}
[%%expect{|
-Line _, characters 0-36:
-Error (warning 22): Fields are not sorted!
+type t = { b : int; a : int; }
|}]
(* Extension with a path argument *)
let () =
Driver.register_transformation "plop"
~rules:[Context_free.Rule.extension
(Extension.declare_with_path_arg "plop"
Expression
Ast_pattern.(pstr nil)
(fun ~loc ~path:_ ~arg ->
let open Ast_builder.Default in
match arg with
| None -> estring ~loc "-"
| Some { loc; txt } -> estring ~loc (Longident.name txt)))]
[%%expect{|
+Line _, characters 11-418:
+Error: This expression has type 'a list
+ but an expression was expected of type
+ Context_free.Rule.t Ppxlib__Import.sexp_list
|}]
let _ = Caml.Printf.sprintf "%s\n" [%plop]
[%%expect{|
-- : string = "-\n"
+Line _, characters 8-27:
+Error: Unbound module Caml
|}]
let _ = Caml.Printf.sprintf "%s\n" [%plop.Truc]
[%%expect{|
-- : string = "Truc\n"
+Line _, characters 8-27:
+Error: Unbound module Caml
|}]
let _ = Caml.Printf.sprintf "%s\n" [%plop.Truc.Bidule]
[%%expect{|
-- : string = "Truc.Bidule\n"
+Line _, characters 8-27:
+Error: Unbound module Caml
|}]
patdiff (internal) (exit 1)
(cd _build/default && /usr/bin/patdiff -keep-whitespace -location-style omake -ascii test/driver/attributes/test.ml test/driver/attributes/test.ml.corrected)
-test/driver/attributes/test.ml
+test/driver/attributes/test.ml.corrected
File "test/driver/attributes/test.ml", line 11, characters 0-1:
#use "topfind";;
#require "base";;
open Base
open Ppxlib
let () = Driver.enable_checks ()
let x = 1 [@@foo]
[%%expect{|
-Line _, characters 13-16:
-Error: Attribute `foo' was not used
+Unknown directive `require'.
+Line _, characters 5-9:
+Error: Unbound module Base
+Line _, characters 30-32:
+Error: This expression has type unit but an expression was expected of type
+ Ppxlib__Import.unit
+val x : int = 1
|}]
let f x = 1 [@@deprecatd "..."]
[%%expect{|
-Line _, characters 15-24:
-Error: Attribute `deprecatd' was not used.
-Hint: Did you mean deprecated?
+Line _, characters 6-7:
+Error (warning 27): unused variable x.
|}]
let attr : _ Attribute.t =
Attribute.declare "blah"
Attribute.Context.type_declaration
Ast_pattern.(__)
ignore
[%%expect{|
-val attr : (type_declaration, unit) Attribute.t = <abstr>
+Line _, characters 20-26:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
type t = int [@blah]
[%%expect{|
-Line _, characters 15-19:
-Error: Attribute `blah' was not used.
-Hint: `blah' is available for type declarations but is used here in the
-context of a core type.
-Did you put it at the wrong level?
+type t = int
|}]
let attr : _ Attribute.t =
Attribute.declare "blah"
Attribute.Context.expression
Ast_pattern.(__)
ignore
[%%expect{|
-val attr : (expression, unit) Attribute.t = <abstr>
+Line _, characters 20-26:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
|}]
type t = int [@blah]
[%%expect{|
-Line _, characters 15-19:
-Error: Attribute `blah' was not used.
-Hint: `blah' is available for expressions and type declarations but is used
-here in the context of a core type.
-Did you put it at the wrong level?
+type t = int
|}]
(* Attribute drops *)
let faulty_transformation = object
inherit Ast_traverse.map as super
method! expression e =
match e.pexp_desc with
| Pexp_constant c ->
Ast_builder.Default.pexp_constant ~loc:e.pexp_loc c
| _ -> super#expression e
end
[%%expect{|
val faulty_transformation : Ast_traverse.map = <obj>
|}]
let () =
Driver.register_transformation "faulty" ~impl:faulty_transformation#structure
let x = (42 [@foo])
[%%expect{|
-Line _, characters 14-17:
-Error: Attribute `foo' was silently dropped
+Line _, characters 33-41:
+Error: This expression has type string but an expression was expected of type
+ Ppxlib__Import.string
+val x : t = 42
|}]
type t1 = < >
type t2 = < t1 >
type t3 = < (t1[@foo]) >
[%%expect{|
type t1 = < >
type t2 = < >
-Line _, characters 17-20:
-Error: Attribute `foo' was not used
+type t3 = < >
|}]
------------------------------------------------------------------------------------------
Fri 16 Aug 2019 07:00:31 PM EDT
exited abnormally with code 1
We currently whilelist merlin attributes as they can safely be dropped. Reason needs something similar, cf janestreet/ppx_inline_test#15.
To be more generic, we can simply whitelist all attributes with a name starting with _
. We should also whitelist specific existing reason attributes to make things simpler.
I'm currently developing a deriving rewriter which is extending type-conv
and is being registered using Type_conv.add "name"
. When I run -print-transformations
the standalone rewriter gives me only type_conv
. It would be great if it will print all the generators registered for type_conv.
P.S. I actually have a bug at the moment that standalone rewriter is not linked with my code and complains like Error: ppxlib_type_conv: 'name' is not a supported type type-conv generator
. It would be great to know for sure (using switch above) that the library that registers generator is not linked.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.