From eaf461516ed8a4206ffdade053dd99cc9288bcf2 Mon Sep 17 00:00:00 2001 From: Ulf Wiger Date: Thu, 18 Sep 2014 17:31:03 +0200 Subject: [PATCH] set uwiger/parse_trans as root, fix email & copyrights --- README.md | 16 +- doc/README.md | 4 +- doc/ct_expand.md | 76 ++++-- doc/edoc-info | 1 + doc/exprecs.md | 96 +++++-- doc/parse_trans.md | 531 +++++++++++++++++++------------------ doc/parse_trans_codegen.md | 157 ++++++++--- doc/parse_trans_mod.md | 92 ++++--- doc/parse_trans_pp.md | 86 +++--- include/codegen.hrl | 8 +- include/exprecs.hrl | 8 +- rebar.config | 4 +- src/exprecs.erl | 8 +- src/parse_trans_mod.erl | 4 +- 14 files changed, 618 insertions(+), 473 deletions(-) diff --git a/README.md b/README.md index fbeb83e..952e9a2 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -#The parse_trans application# +# The parse_trans application # -##Modules## +## Modules ## - - - - - -
ct_expand
exprecs
parse_trans
parse_trans_codegen
parse_trans_mod
parse_trans_pp
+ct_expand +exprecs +parse_trans +parse_trans_codegen +parse_trans_mod +parse_trans_pp diff --git a/doc/README.md b/doc/README.md index 13e2c04..14bd178 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,9 +1,9 @@ -#The parse_trans application# +# The parse_trans application # -##Modules## +## Modules ## diff --git a/doc/ct_expand.md b/doc/ct_expand.md index 066772b..34d55f6 100644 --- a/doc/ct_expand.md +++ b/doc/ct_expand.md @@ -1,6 +1,6 @@ -#Module ct_expand# +# Module ct_expand # * [Description](#description) * [Data Types](#types) * [Function Index](#index) @@ -8,13 +8,12 @@ Compile-time expansion utility. +__Authors:__ : Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)). + +## Description ## -__Authors:__ : Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)). - -##Description## - This module serves as an example of parse_trans-based transforms, but might also be a useful utility in its own right. @@ -22,50 +21,75 @@ The transform searches for calls to the pseudo-function `ct_expand:term(Expr)`, and then replaces the call site with the result of evaluating `Expr` at compile-time. + + For example, the line + + `ct_expand:term(lists:sort([3,5,2,1,4]))` + + would be expanded at compile-time to `[1,2,3,4,5]`. + + ct_expand has now been extended to also evaluate calls to local functions. See examples/ct_expand_test.erl for some examples. + + A debugging facility exists: passing the option {ct_expand_trace, Flags} as an option, -or adding a compiler attribute -ct_expand_trace(Flags) will enable a form of call trace.`Flags` can be `[]` (no trace) or `[F]`, where `F` is `c` (call trace), +or adding a compiler attribute -ct_expand_trace(Flags) will enable a form of call trace. + + +`Flags` can be `[]` (no trace) or `[F]`, where `F` is `c` (call trace), `r` (return trace), or `x` (exception trace)'. -##Data Types## +## Data Types ## -###form()## +### form() ### -
form() = any()
+

+form() = any()
+
-###forms()## + + +### forms() ### -
forms() = [form()]
+

+forms() = [form()]
+
-###options()## + + +### options() ### -
options() = [{atom(), any()}]
+

+options() = [{atom(), any()}]
+
+ + -##Function Index## +## Function Index ##
extract_fun/3
lfun_rewrite/2
parse_transform/2
@@ -73,34 +97,30 @@ or adding a compiler attribute -ct_expand_trace(Flags) will enable a form of cal -##Function Details## +## Function Details ## -###extract_fun/3## - - - +### extract_fun/3 ### `extract_fun(Name, Arity, Forms) -> any()` + -###lfun_rewrite/2## - - - +### lfun_rewrite/2 ### `lfun_rewrite(Exprs, Forms) -> any()` + -###parse_transform/2## +### parse_transform/2 ### - - -
parse_transform(Forms::forms(), Options::options()) -> forms()
-

+

+parse_transform(Forms::forms(), Options::options()) -> forms()
+
+
diff --git a/doc/edoc-info b/doc/edoc-info index 1c637d7..7665186 100644 --- a/doc/edoc-info +++ b/doc/edoc-info @@ -1,3 +1,4 @@ +%% encoding: UTF-8 {application,parse_trans}. {packages,[]}. {modules,[ct_expand,exprecs,parse_trans,parse_trans_codegen,parse_trans_mod, diff --git a/doc/exprecs.md b/doc/exprecs.md index f0adb7c..80e5c79 100644 --- a/doc/exprecs.md +++ b/doc/exprecs.md @@ -1,6 +1,6 @@ -#Module exprecs# +# Module exprecs # * [Description](#description) * [Data Types](#types) * [Function Index](#index) @@ -8,13 +8,10 @@ Parse transform for generating record access functions. +__Authors:__ : Ulf Wiger ([`ulf@wiger.net`](mailto:ulf@wiger.net)). + - - -__Authors:__ : Ulf Wiger ([`ulf.wiger@ericsson.com`](mailto:ulf.wiger@ericsson.com)). - -##Description## - +## Description ## This parse transform can be used to reduce compile-time dependencies in large systems. @@ -36,8 +33,13 @@ records without the need for compile-time dependencies. Whenever record definitions need to be exported from a module, inserting a compiler attribute, `export_records([RecName|...])` causes this transform -to lay out access functions for the exported records:As an example, consider the following module: -
+to lay out access functions for the exported records:
+
+
+As an example, consider the following module:
+
+```
+
   -module(test_exprecs).
   -export([f/0]).
   -compile({parse_transform, exprecs}).
@@ -47,10 +49,18 @@ to lay out access functions for the exported records:As an example, consider the
   -record(s,{a}).
   -export_records([r,s]).
   f() ->
-      {new,'#new-r'([])}.
+ {new,'#new-r'([])}. +``` + + Compiling this (assuming exprecs is in the path) will produce the -following code.
+following code.
+
+
+
+```
+
   -module(test_exprecs).
   -compile({pt_pp_src,true}).
   -export([f/0]).
@@ -327,13 +337,25 @@ following code.
   '#lens-s'(Attr) ->
       error(bad_record_op, ['#lens-s', Attr]).
   f() ->
-      {new,'#new-r'([])}.
+ {new,'#new-r'([])}. +``` + + It is possible to modify the naming rules of exprecs, through the use -of the following attributes (example reflecting the current rules):
+of the following attributes (example reflecting the current rules):
+
+
+
+```
+
   -exprecs_prefix(["#", operation, "-"]).
   -exprecs_fname([prefix, record]).
-  -exprecs_vfname([fname, "__", version]).
The lists must contain strings or any of the following control atoms: + -exprecs_vfname([fname, "__", version]). +``` + + +The lists must contain strings or any of the following control atoms: * in `exprecs_prefix`: `operation` @@ -343,9 +365,13 @@ of the following attributes (example reflecting the current rules):
 
 
 
+
 Exprecs will substitute the control atoms with the string values of the
 corresponding items. The result will then be flattened and converted to an
-atom (a valid function or type name).`operation` is one of:
+atom (a valid function or type name).
+
+
+`operation` is one of:
 
 
 
@@ -451,35 +477,47 @@ atom (a valid function or type name).`operation` is one of:
 
 
 
-##Data Types##
+## Data Types ##
 
 
 
 
-###form()##
+### form() ###
 
 
 
-
form() = any()
+

+form() = any()
+
-###forms()## + + +### forms() ### -
forms() = [form()]
+

+forms() = [form()]
+
-###options()## + + +### options() ### -
options() = [{atom(), any()}]
+

+options() = [{atom(), any()}]
+
+ + -##Function Index## +## Function Index ##
parse_transform/2
@@ -487,16 +525,16 @@ atom (a valid function or type name).`operation` is one of: -##Function Details## +## Function Details ## -###parse_transform/2## +### parse_transform/2 ### - - -
parse_transform(Forms::forms(), Options::options()) -> forms()
-

+

+parse_transform(Forms::forms(), Options::options()) -> forms()
+
+
diff --git a/doc/parse_trans.md b/doc/parse_trans.md index 150d32d..8f3e7b8 100644 --- a/doc/parse_trans.md +++ b/doc/parse_trans.md @@ -1,6 +1,6 @@ -#Module parse_trans# +# Module parse_trans # * [Description](#description) * [Data Types](#types) * [Function Index](#index) @@ -8,79 +8,107 @@ Generic parse transform library for Erlang. +__Authors:__ : Ulf Wiger ([`ulf.wiger@feuerlabs.com`](mailto:ulf.wiger@feuerlabs.com)). + +## Description ## -__Authors:__ : Ulf Wiger ([`ulf.wiger@feuerlabs.com`](mailto:ulf.wiger@feuerlabs.com)). - -##Description## - ... + -##Data Types## +## Data Types ## -###form()## +### form() ### -
form() = any()
+

+form() = any()
+
-###forms()## + + +### forms() ### -
forms() = [form()]
+

+forms() = [form()]
+
-###insp_f()## + + +### insp_f() ### -
insp_f() = fun((type(), form(), #context{}, A) -> {boolean(), A})
+

+insp_f() = fun((type(), form(), #context{}, A) -> {boolean(), A})
+
-###options()## + + +### options() ### -
options() = [{atom(), any()}]
+

+options() = [{atom(), any()}]
+
-###type()## + + +### type() ### -
type() = atom()
+

+type() = atom()
+
-###xform_f_df()## + + +### xform_f_df() ### -
xform_f_df() = fun((type(), form(), #context{}, Acc) -> {form(), Acc} | {forms(), form(), forms(), Acc})
+

+xform_f_df() = fun((type(), form(), #context{}, Acc) -> {form(), Acc} | {forms(), form(), forms(), Acc})
+
-###xform_f_rec()## + + +### xform_f_rec() ### -
xform_f_rec() = fun((type(), form(), #context{}, Acc) -> {form(), boolean(), Acc} | {forms(), form(), forms(), boolean(), Acc})
+

+xform_f_rec() = fun((type(), form(), #context{}, Acc) -> {form(), boolean(), Acc} | {forms(), form(), forms(), boolean(), Acc})
+
+ + -##Function Index## +## Function Index ##
context/2 @@ -102,295 +130,279 @@ Makes one pass.
-##Function Details## +## Function Details ## -###context/2## +### context/2 ### +

+context(X1::Attr, Context) -> any()
+
+ +
  • Attr = module | function | arity | options
-
context(X1::Attr, Context) -> any()
-
  • Attr = module | function | arity | options
+Accessor function for the Context record. + + +### depth_first/4 ### - - -Accessor function for the Context record. - -###depth_first/4## - - - - -
depth_first(Fun::xform_f_df(), Acc, Forms::forms(), Options::options()) -> {forms(), Acc} | {error, list()}
-

+

+depth_first(Fun::xform_f_df(), Acc, Forms::forms(), Options::options()) -> {forms(), Acc} | {error, list()}
+
+
-###do_depth_first/4## +### do_depth_first/4 ### - - -
do_depth_first(F::xform_f_df(), Acc::term(), Forms::forms(), Context::#context{}) -> {forms(), term()}
-

+

+do_depth_first(F::xform_f_df(), Acc::term(), Forms::forms(), Context::#context{}) -> {forms(), term()}
+
+
-###do_insert_forms/4## +### do_insert_forms/4 ### - - -
do_insert_forms(X1::above | below, Insert::forms(), Forms::forms(), Context::#context{}) -> forms()
-

+

+do_insert_forms(X1::above | below, Insert::forms(), Forms::forms(), Context::#context{}) -> forms()
+
+
-###do_inspect/4## +### do_inspect/4 ### - - -
do_inspect(F::insp_f(), Acc::term(), Forms::forms(), Context::#context{}) -> term()
-

+

+do_inspect(F::insp_f(), Acc::term(), Forms::forms(), Context::#context{}) -> term()
+
+
-###do_transform/4## +### do_transform/4 ### - - -
do_transform(F::xform_f_rec(), Acc::term(), Forms::forms(), Context::#context{}) -> {forms(), term()}
-

+

+do_transform(F::xform_f_rec(), Acc::term(), Forms::forms(), Context::#context{}) -> {forms(), term()}
+
+
-###error/3## +### error/3 ### + + +

+error(R::Reason, F::Form, I::Info) -> throw()
+
+ +
  • Info = [{Key, Value}]
+Used to report errors detected during the parse transform. -
error(R::Reason, F::Form, I::Info) -> throw()
-
  • Info = [{Key, Value}]
- - - - - - -Used to report errors detected during the parse transform. - -###export_function/3## - - + +### export_function/3 ### `export_function(F, Arity, Forms) -> any()` + -###format_error/1## +### format_error/1 ### - - -
format_error(Error::{atom(), term()}) -> iolist()
-

+

+format_error(Error::{atom(), term()}) -> iolist()
+
+
-###format_exception/2## +### format_exception/2 ### +

+format_exception(Class, Reason) -> String
+
+
+ +Equivalent to [`format_exception(Class, Reason, 4)`](#format_exception-3). + + +### format_exception/3 ### -
format_exception(Class, Reason) -> String
-

- - - - -Equivalent to [`format_exception(Class, Reason, 4)`](#format_exception-3). - -###format_exception/3## - - - - -
format_exception(Class, Reason, Lines) -> String
-
  • Class = error | throw | exit
  • Reason = term()
  • Lines = integer() | infinity
- - +

+format_exception(Class, Reason, Lines) -> String
+
+
  • Class = error | throw | exit
  • Reason = term()
  • Lines = integer() | infinity
Produces a few lines of user-friendly formatting of exception info + + This function is very similar to the exception pretty-printing in the shell, but returns a string that can be used as error info e.g. by error forms handled by [`return/2`](#return-2). By default, the first 4 lines of the pretty-printed exception info are returned, but this can be controlled -with the `Lines` parameter.Note that a stacktrace is generated inside this function. - -###function_exists/3## +with the `Lines` parameter. +Note that a stacktrace is generated inside this function. + + +### function_exists/3 ### -
function_exists(Fname::atom(), Arity::integer(), Forms) -> boolean()
-

+

+function_exists(Fname::atom(), Arity::integer(), Forms) -> boolean()
+
+
+Checks whether the given function is defined in Forms. + + +### get_attribute/2 ### +

+get_attribute(A, Forms) -> any()
+
-Checks whether the given function is defined in Forms. - -###get_attribute/2## - - - - -
get_attribute(A, Forms) -> any()
-
  • A = atom()
- - - - -Returns the value of the first occurence of attribute A. - -###get_attribute/3## +
  • A = atom()
+Returns the value of the first occurence of attribute A. + +### get_attribute/3 ### `get_attribute(A, Forms, Undef) -> any()` + -###get_file/1## +### get_file/1 ### +

+get_file(Forms) -> string()
+
+
-
get_file(Forms) -> string()
-

+Returns the name of the file being compiled. + + +### get_module/1 ### +

+get_module(Forms) -> atom()
+
+
+Returns the name of the module being compiled. + -Returns the name of the file being compiled. - -###get_module/1## - - - - -
get_module(Forms) -> atom()
-

- - - - - -Returns the name of the module being compiled. - -###get_orig_syntax_tree/1## - - - - -
get_orig_syntax_tree(File) -> Forms
-

- - +### get_orig_syntax_tree/1 ### +

+get_orig_syntax_tree(File) -> Forms
+
+
Fetches a Syntax Tree representing the code before pre-processing, that is, including record and macro definitions. Note that macro definitions must be syntactically complete forms (this function -uses epp_dodger). - -###get_pos/1## - - - - -
get_pos(I::list()) -> integer()
-

+uses epp_dodger). + + +### get_pos/1 ### +

+get_pos(I::list()) -> integer()
+
+
Tries to retrieve the line number from an erl_syntax form. Returns a -(very high) dummy number if not successful. - -###initial_context/2## - - - - -
initial_context(Forms, Options) -> #context{}
-

+(very high) dummy number if not successful. + +### initial_context/2 ### +

+initial_context(Forms, Options) -> #context{}
+
+
Initializes a context record. When traversing through the form list, the context is updated to reflect the current function and arity. Static elements in the context are the file name, the module -name and the options passed to the transform function. +name and the options passed to the transform function. + -###inspect/4## +### inspect/4 ### +

+inspect(F::Fun, Acc::Forms, Forms::Acc, Options) -> NewAcc
+
+ +
  • Fun = function()
-
inspect(F::Fun, Acc::Forms, Forms::Acc, Options) -> NewAcc
-
  • Fun = function()
+Equvalent to do_inspect(Fun,Acc,Forms,initial_context(Forms,Options)). + + +### optionally_pretty_print/3 ### - - -Equvalent to do_inspect(Fun,Acc,Forms,initial_context(Forms,Options)). - -###optionally_pretty_print/3## - - - - -
optionally_pretty_print(Result::forms(), Options::options(), Context::#context{}) -> ok
-

+

+optionally_pretty_print(Result::forms(), Options::options(), Context::#context{}) -> ok
+
+
-###plain_transform/2## - - - - -
plain_transform(Fun, Forms) -> forms()
- +### plain_transform/2 ### +

+plain_transform(Fun, Forms) -> forms()
+
+ @@ -400,15 +412,24 @@ representation. The intention of this transform is for the fun to have a catch-all clause returning `continue`. This will ensure that it stays robust against additions to the language. + + `Fun(Form)` must return either of the following: + + * `NewForm` - any valid form * `continue` - dig into the sub-expressions of the form * `{done, NewForm}` - Replace `Form` with `NewForm`; return all following forms unchanged -* `{error, Reason}` - Abort transformation with an error message.Example - This transform fun would convert all instances of `P ! Msg` to +* `{error, Reason}` - Abort transformation with an error message. + + +Example - This transform fun would convert all instances of `P ! Msg` to `gproc:send(P, Msg)`: -
+
+```
+
   parse_transform(Forms, _Options) ->
       parse_trans:plain_transform(fun do_transform/1, Forms).
   do_transform({'op', L, '!', Lhs, Rhs}) ->
@@ -417,80 +438,74 @@ forms unchanged
       {call, L, {remote, L, {atom, L, gproc}, {atom, L, send}},
        [NewLhs, NewRhs]};
   do_transform(_) ->
-      continue.
- -###pp_beam/1## - - - - -
pp_beam(Beam::file:filename()) -> string() | {error, Reason}
-

+ continue. +``` + + +### pp_beam/1 ### +

+pp_beam(Beam::file:filename()) -> string() | {error, Reason}
+
+
Reads debug_info from the beam file Beam and returns a string containing -the pretty-printed corresponding erlang source code. - -###pp_beam/2## - - - - -
pp_beam(Beam::filename(), Out::filename()) -> ok | {error, Reason}
-

+the pretty-printed corresponding erlang source code. + +### pp_beam/2 ### +

+pp_beam(Beam::filename(), Out::filename()) -> ok | {error, Reason}
+
+
Reads debug_info from the beam file Beam and pretty-prints it as -Erlang source code, storing it in the file Out. - -###pp_src/2## - - - - -
pp_src(Res::Forms, Out::filename()) -> ok
-

+Erlang source code, storing it in the file Out. + +### pp_src/2 ### +

+pp_src(Res::Forms, Out::filename()) -> ok
+
+
Pretty-prints the erlang source code corresponding to Forms into Out + -###replace_function/4## - - - +### replace_function/4 ### `replace_function(F, Arity, NewForm, Forms) -> any()` + -###return/2## - - - - -
return(Forms, Context) -> Forms | {error, Es, Ws} | {warnings, Forms, Ws}
-

- +### return/2 ### +

+return(Forms, Context) -> Forms | {error, Es, Ws} | {warnings, Forms, Ws}
+
+
Checks the transformed result for errors and warnings - Errors and warnings can be produced from inside a parse transform, with a bit of care. The easiest way is to simply produce an `{error, Err}` or `{warning, Warn}` form in place. This function finds such forms, and removes them from the form list (otherwise, the linter will crash), and -produces a return value that the compiler can work with.The format of the `error` and `warning` "forms" must be +produces a return value that the compiler can work with. + + +The format of the `error` and `warning` "forms" must be `{Tag, {Pos, Module, Info}}`, where: * `Tag :: error | warning` @@ -504,24 +519,21 @@ produces a return value that the compiler can work with.The format of the `error - If the error is in the form of a caught exception, `Info` may be produced -using the function [`format_exception/2`](#format_exception-2). - -###revert/1## - - - - -
revert(Tree) -> Forms
-

+using the function [`format_exception/2`](#format_exception-2). + + +### revert/1 ### +

+revert(Tree) -> Forms
+
+
Reverts back from Syntax Tools format to Erlang forms. - Note that the Erlang forms are a subset of the Syntax Tools syntax tree, so this function is safe to call even on a list of regular Erlang forms. @@ -532,22 +544,20 @@ Note2: R16B03 introduced a bug, where forms produced by This function works around that limitation, after first verifying that it's necessary to do so. Use of the workaround can be forced with the help of the `parse_trans` environment variable {revert_workaround, true}. This -variable will be removed when R16B03 is no longer 'supported'. - -###revert_form/1## - - - - -
revert_form(F::Tree) -> Form
-

+variable will be removed when R16B03 is no longer 'supported'. + + +### revert_form/1 ### +

+revert_form(F::Tree) -> Form
+
+
Reverts a single form back from Syntax Tools format to Erlang forms. - `erl_syntax:revert/1` has had a long-standing bug where it doesn't completely revert attribute forms. This function deals properly with those cases. @@ -563,28 +573,29 @@ Note2: R16B03 introduced a bug, where forms produced by This function works around that limitation, after first verifying that it's necessary to do so. Use of the workaround can be forced with the help of the `parse_trans` environment variable {revert_workaround, true}. This -variable will be removed when R16B03 is no longer 'supported'. +variable will be removed when R16B03 is no longer 'supported'. -###top/3## + + +### top/3 ### - - -
top(F::function(), Forms::forms(), Options::list()) -> forms() | {error, term()}
-

+

+top(F::function(), Forms::forms(), Options::list()) -> forms() | {error, term()}
+
+
-###transform/4## +### transform/4 ### +

+transform(Fun, Acc, Forms, Options) -> {TransformedForms, NewAcc}
+
+ +
  • Fun = function()
  • Options = [{Key, Value}]
-
transform(Fun, Acc, Forms, Options) -> {TransformedForms, NewAcc}
-
  • Fun = function()
  • Options = [{Key, Value}]
- - - - -Makes one pass \ No newline at end of file +Makes one pass diff --git a/doc/parse_trans_codegen.md b/doc/parse_trans_codegen.md index 7bb9d04..e2bdc39 100644 --- a/doc/parse_trans_codegen.md +++ b/doc/parse_trans_codegen.md @@ -1,24 +1,24 @@ -#Module parse_trans_codegen# +# Module parse_trans_codegen # * [Description](#description) * [Function Index](#index) * [Function Details](#functions) Parse transform for code generation pseduo functions. +__Authors:__ : Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)). + +## Description ## -__Authors:__ : Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)). - -##Description## - ... + -##Function Index## +## Function Index ##
format_error/1
parse_transform/2 @@ -29,30 +29,24 @@ representing the abstract form of that code.
-##Function Details## +## Function Details ## -###format_error/1## - - - +### format_error/1 ### `format_error(E) -> any()` + -###parse_transform/2## - - - - -
parse_transform(Forms, Options) -> NewForms
-

- - +### parse_transform/2 ### +

+parse_transform(Forms, Options) -> NewForms
+
+
@@ -60,20 +54,33 @@ Searches for calls to pseudo functions in the module `codegen`, and converts the corresponding erlang code to a data structure representing the abstract form of that code. + + The purpose of these functions is to let the programmer write the actual code that is to be generated, rather than manually writing abstract forms, which is more error prone and cannot be checked by the compiler until the generated module is compiled. + + Supported functions: -##gen_function/2## + + + +## gen_function/2 ## + Usage: `codegen:gen_function(Name, Fun)` + + Substitutes the abstract code for a function with name `Name` -and the same behaviour as `Fun`.`Fun` can either be a anonymous `fun`, which is then converted to +and the same behaviour as `Fun`. + + +`Fun` can either be a anonymous `fun`, which is then converted to a named function, or it can be an `implicit fun`, e.g. `fun is_member/2`. In the latter case, the referenced function is fetched and converted to an abstract form representation. It is also renamed @@ -82,79 +89,141 @@ so that the generated function has the name `Name`. Another alternative is to wrap a fun inside a list comprehension, e.g. -
+
+```
+
   f(Name, L) ->
       codegen:gen_function(
           Name,
           [ fun({'$var',X}) ->
                {'$var', Y}
-            end || {X, Y} <- L ]).
+ end || {X, Y} <- L ]). +``` + Calling the above with `f(foo, [{1,a},{2,b},{3,c}])` will result in generated code corresponding to: -
+
+```
+
   foo(1) -> a;
   foo(2) -> b;
-  foo(3) -> c.
+ foo(3) -> c. +``` + + + + +## gen_functions/1 ## -##gen_functions/1## Takes a list of `{Name, Fun}` tuples and produces a list of abstract data objects, just as if one had written `[codegen:gen_function(N1,F1),codegen:gen_function(N2,F2),...]`. -##exprs/1## + + + +## exprs/1 ## + Usage: `codegen:exprs(Fun)` + + `Fun` is either an anonymous function, or an implicit fun with only one function clause. This "function" takes the body of the fun and produces a data type representing the abstract form of the list of expressions in the body. The arguments of the function clause are ignored, but can be used to ensure that all necessary variables are known to the compiler. -##gen_module/3## + + + +## gen_module/3 ## + Generates abstract forms for a complete module definition. + + Usage: `codegen:gen_module(ModuleName, Exports, Functions)` + + `ModuleName` is either an atom or a `{'$var', V}` reference. + + `Exports` is a list of `{Function, Arity}` tuples. + + `Functions` is a list of `{Name, Fun}` tuples analogous to that for `gen_functions/1`. -##Variable substitution## + + + +## Variable substitution ## + It is possible to do some limited expansion (importing a value bound at compile-time), using the construct `{'$var', V}`, where -`V` is a bound variable in the scope of the call to `gen_function/2`.Example: -
-  gen(Name, X) ->
-     codegen:gen_function(Name, fun(L) -> lists:member({'$var',X}, L) end).
After transformation, calling `gen(contains_17, 17)` will yield the -abstract form corresponding to: -
-  contains_17(L) ->
-     lists:member(17, L).
+`V` is a bound variable in the scope of the call to `gen_function/2`. + + +Example: + +``` + + gen(Name, X) -> + codegen:gen_function(Name, fun(L) -> lists:member({'$var',X}, L) end). +``` + + +After transformation, calling `gen(contains_17, 17)` will yield the +abstract form corresponding to: + +``` + + contains_17(L) -> + lists:member(17, L). +``` + + + + +## Form substitution ## -##Form substitution## It is possible to inject abstract forms, using the construct `{'$form', F}`, where `F` is bound to a parsed form in -the scope of the call to `gen_function/2`.Example: -
+the scope of the call to `gen_function/2`.
+
+
+Example:
+
+```
+
   gen(Name, F) ->
-     codegen:gen_function(Name, fun(X) -> X =:= {'$form',F} end).
After transformation, calling `gen(is_foo, {atom,0,foo})` will yield the + codegen:gen_function(Name, fun(X) -> X =:= {'$form',F} end). +``` + + +After transformation, calling `gen(is_foo, {atom,0,foo})` will yield the abstract form corresponding to: -
+
+```
+
   is_foo(X) ->
-     X =:= foo.
\ No newline at end of file + X =:= foo. +``` + diff --git a/doc/parse_trans_mod.md b/doc/parse_trans_mod.md index e9cae52..84e925f 100644 --- a/doc/parse_trans_mod.md +++ b/doc/parse_trans_mod.md @@ -1,37 +1,43 @@ -#Module parse_trans_mod# +# Module parse_trans_mod # * [Data Types](#types) * [Function Index](#index) * [Function Details](#functions) - - -##Data Types## +## Data Types ## -###compile_options()## +### compile_options() ### -
compile_options() = [term()]
+

+compile_options() = [term()]
+
-###erlang_form()## + + +### erlang_form() ### -
erlang_form() = term()
+

+erlang_form() = term()
+
+ + -##Function Index## +## Function Index ##
abstract_code/1
beam_file/1
compile_and_load_forms/1
compile_and_load_forms/2
compile_options/1
rename_module/2
transform_module/3
@@ -39,80 +45,78 @@ -##Function Details## +## Function Details ## -###abstract_code/1## +### abstract_code/1 ### - - -
abstract_code(BeamFile::binary()) -> erlang_form()
-

+

+abstract_code(BeamFile::binary()) -> erlang_form()
+
+
-###beam_file/1## +### beam_file/1 ### - - -
beam_file(Module::module()) -> binary()
-

+

+beam_file(Module::module()) -> binary()
+
+
-###compile_and_load_forms/1## +### compile_and_load_forms/1 ### - - -
compile_and_load_forms(AbsCode::erlang_form()) -> ok
-

+

+compile_and_load_forms(AbsCode::erlang_form()) -> ok
+
+
-###compile_and_load_forms/2## +### compile_and_load_forms/2 ### - - -
compile_and_load_forms(AbsCode::erlang_form(), Opts::compile_options()) -> ok
-

+

+compile_and_load_forms(AbsCode::erlang_form(), Opts::compile_options()) -> ok
+
+
-###compile_options/1## +### compile_options/1 ### - - -
compile_options(BeamFile::binary() | module()) -> compile_options()
-

+

+compile_options(BeamFile::binary() | module()) -> compile_options()
+
+
-###rename_module/2## +### rename_module/2 ### - - -
rename_module(T::erlang_form(), NewName::module()) -> erlang_form()
-

+

+rename_module(T::erlang_form(), NewName::module()) -> erlang_form()
+
+
-###transform_module/3## - - - +### transform_module/3 ### `transform_module(Mod, PT, Options) -> any()` + diff --git a/doc/parse_trans_pp.md b/doc/parse_trans_pp.md index f2120af..8b4c183 100644 --- a/doc/parse_trans_pp.md +++ b/doc/parse_trans_pp.md @@ -1,31 +1,39 @@ -#Module parse_trans_pp# +# Module parse_trans_pp # * [Description](#description) * [Function Index](#index) * [Function Details](#functions) Generic parse transform library for Erlang. +__Authors:__ : Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)). + +## Description ## -__Authors:__ : Ulf Wiger ([`ulf@feuerlabs.com`](mailto:ulf@feuerlabs.com)). - -##Description## - This module contains some useful utility functions for inspecting the results of parse transforms or code generation. The function `main/1` is called from escript, and can be used to -pretty-print debug info in a .beam file from a Linux shell.Using e.g. the following bash alias: -
-   alias pp='escript $PARSE_TRANS_ROOT/ebin/parse_trans_pp.beam'
+pretty-print debug info in a .beam file from a Linux shell. -a file could be pretty-printed using the following command:`$ pp ex_codegen.beam | less` +Using e.g. the following bash alias: -##Function Index## +``` + + alias pp='escript $PARSE_TRANS_ROOT/ebin/parse_trans_pp.beam' +``` + + +a file could be pretty-printed using the following command: + + +`$ pp ex_codegen.beam | less` + +## Function Index ##
main/1
pp_beam/1 @@ -37,60 +45,54 @@ Erlang source code, storing it in the file Out.
-##Function Details## +## Function Details ## -###main/1## +### main/1 ### - - -
main(X1::[string()]) -> any()
-

+

+main(X1::[string()]) -> any()
+
+
-###pp_beam/1## - - - - -
pp_beam(Beam::filename()) -> string() | {error, Reason}
-

- +### pp_beam/1 ### +

+pp_beam(Beam::filename()) -> string() | {error, Reason}
+
+
Reads debug_info from the beam file Beam and returns a string containing -the pretty-printed corresponding erlang source code. - -###pp_beam/2## - - - - -
pp_beam(Beam::filename(), Out::filename()) -> ok | {error, Reason}
-

+the pretty-printed corresponding erlang source code. + +### pp_beam/2 ### +

+pp_beam(Beam::filename(), Out::filename()) -> ok | {error, Reason}
+
+
Reads debug_info from the beam file Beam and pretty-prints it as -Erlang source code, storing it in the file Out. - -###pp_src/2## - - - - -
pp_src(Forms0::Forms, Out::filename()) -> ok
-

+Erlang source code, storing it in the file Out. + +### pp_src/2 ### +

+pp_src(Forms0::Forms, Out::filename()) -> ok
+
+
Pretty-prints the erlang source code corresponding to Forms into Out + diff --git a/include/codegen.hrl b/include/codegen.hrl index c5bbb55..a1dfd49 100644 --- a/include/codegen.hrl +++ b/include/codegen.hrl @@ -10,16 +10,16 @@ %% %% The Original Code is parse_trans-2.0. %% -%% Copyright (c) 2010 Erlang Solutions Ltd. +%% Copyright (c) 2014 Ericsson AB %% %% Contributor(s): ______________________________________. %%------------------------------------------------------------------- %% File : codegen.hrl -%% @author : Ulf Wiger +%% @author : Ulf Wiger %% @end -%% Description : +%% Description : %% -%% Created : 25 Feb 2010 by Ulf Wiger +%% Created : 25 Feb 2010 by Ulf Wiger %%------------------------------------------------------------------- -compile({parse_transform, parse_trans_codegen}). diff --git a/include/exprecs.hrl b/include/exprecs.hrl index 1faab7e..6d92609 100644 --- a/include/exprecs.hrl +++ b/include/exprecs.hrl @@ -10,16 +10,16 @@ %% %% The Original Code is exprecs-0.2. %% -%% Copyright (c) 2010 Erlang Solutions Ltd. +%% Copyright (c) 2014 Ericsson AB %% %% Contributor(s): ______________________________________. %%------------------------------------------------------------------- %% File : exprecs.hrl -%% @author : Ulf Wiger +%% @author : Ulf Wiger %% @end -%% Description : +%% Description : %% -%% Created : 25 Feb 2010 by Ulf Wiger +%% Created : 25 Feb 2010 by Ulf Wiger %%------------------------------------------------------------------- -compile({parse_transform, exprecs}). diff --git a/rebar.config b/rebar.config index fea8d77..6c08fe5 100644 --- a/rebar.config +++ b/rebar.config @@ -5,8 +5,8 @@ {erl_opts, [debug_info]}. {xref_checks, [undefined_function_calls]}. -{deps, [{edown, ".*", {git, "git://github.com/esl/edown.git", "HEAD"}}]}. +{deps, [{edown, ".*", {git, "git://github.com/uwiger/edown.git", "0.5"}}]}. {edoc_opts, [{doclet, edown_doclet}, {top_level_readme, {"./README.md", - "http://github.com/esl/parse_trans"}}]}. + "http://github.com/uwiger/parse_trans"}}]}. diff --git a/src/exprecs.erl b/src/exprecs.erl index 9e41bbe..4e19e91 100755 --- a/src/exprecs.erl +++ b/src/exprecs.erl @@ -10,7 +10,7 @@ %% %% The Original Code is exprecs-0.2. %% -%% Copyright (c) 2010 Erlang Solutions Ltd. +%% Copyright (c) 2014 Ericsson AB %% The Initial Developer of the Original Code is Ericsson AB. %% Portions created by Ericsson are Copyright (C), 2006, Ericsson AB. %% All Rights Reserved. @@ -19,12 +19,12 @@ %%------------------------------------------------------------------- %% File : exprecs.erl -%% @author : Ulf Wiger +%% @author : Ulf Wiger %% @end %% Description : %% -%% Created : 13 Feb 2006 by Ulf Wiger -%% Rewritten: Jan-Feb 2010 by Ulf Wiger +%% Created : 13 Feb 2006 by Ulf Wiger +%% Rewritten: Jan-Feb 2010 by Ulf Wiger %%------------------------------------------------------------------- %% @doc Parse transform for generating record access functions. diff --git a/src/parse_trans_mod.erl b/src/parse_trans_mod.erl index 27cb090..2dbbf8e 100644 --- a/src/parse_trans_mod.erl +++ b/src/parse_trans_mod.erl @@ -1,5 +1,5 @@ %%============================================================================ -%% Copyright 2011 Erlang Solutions Ltd. +%% Copyright 2014 Ulf Wiger %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ %% limitations under the License. %%============================================================================ %% -%% Based on meck_mod.erl from http://github.com/esl/meck.git +%% Based on meck_mod.erl from http://github.com/eproxus/meck.git %% Original author: Adam Lindberg %% -module(parse_trans_mod).