diff --git a/docs/doc/api_interface.html b/docs/doc/api_interface.html new file mode 100644 index 00000000..818cc12d --- /dev/null +++ b/docs/doc/api_interface.html @@ -0,0 +1,112 @@ + + + + +Module api_interface + + + + +
+ +

Module api_interface

+This module provides API functions that map the textual selection of a code fragment to + its internal represenation. + +

Authors: Huiqing Li (H.Li@kent.ac.uk).

+ +

Description

This module provides API functions that map the textual selection of a code fragment to + its internal represenation. + +

Function Index

+ + + + + + + + + + +
expr_to_fun/2Return the AST of the function to which Exp (an expression node) belongs.
pos_to_expr/3Returns the largest, left-most expression enclosed by the start and end locations.
pos_to_expr1/3
pos_to_expr_list/2Return the expression sequence enclosed by start and end locations.
pos_to_fun_def/2Returns the AST representation of the function definition in which the + location specified by Pos falls.
pos_to_fun_name/2Returns information about the function name which occurs at the specified + position in the code.
pos_to_node/3Returns the outmost Node which encloses the cursor and + makes Pred(Node) return true.
pos_to_var/2Returns the variable node at position Pos.
pos_to_var_name/2Returns the variable name that occurs at the position specified by position Pos.
range_to_node/3Returns the largest, left-most Node which is enclosed by the location range specified, + and also makes Pred(Node) return true.
+ +

Function Details

+ +

expr_to_fun/2

+
+

expr_to_fun(Tree::syntaxTree(), Exp::syntaxTree()) -> {ok, syntaxTree()} | {error, none}

+

Return the AST of the function to which Exp (an expression node) belongs. + -spec(expr_to_fun(Tree::syntaxTree(), Exp::syntaxTree())->{ok, syntaxTree()} | {error, none}).

+ +

pos_to_expr/3

+
+

pos_to_expr(Tree::syntaxTree(), Start::Pos, End::Pos) -> {ok, syntaxTree()} | {error, string()} +

+

Returns the largest, left-most expression enclosed by the start and end locations. +

+

See also: pos_to_fun_def/2, pos_to_fun_name/2.

+ +

pos_to_expr1/3

+
+

pos_to_expr1(FileOrTree, Start, End) -> any()

+
+ +

pos_to_expr_list/2

+
+

pos_to_expr_list(FileOrTree::filename() | syntaxTree(), X2::{Start::pos(), End::pos()}) -> [syntaxTree()]

+

Return the expression sequence enclosed by start and end locations.

+ +

pos_to_fun_def/2

+
+

pos_to_fun_def(FileOrTree::any(), Pos::pos()) -> {ok, syntaxTree()} | {error, string()}

+

Returns the AST representation of the function definition in which the + location specified by Pos falls. +

+

See also: pos_to_fun_name/2.

+ +

pos_to_fun_name/2

+
+

pos_to_fun_name(Node::syntaxTree(), Pos::{integer(), integer()}) -> {ok, {Mod, Fun, Arity, OccurPos, DefPos}} | {error, string()} +

+

Returns information about the function name which occurs at the specified + position in the code. If successful, the returned information contains: + the module in which the function is defined, the function name, the + function's arity, the occurrence position (same as Pos), and the defining + position of this function. +

+

See also: pos_to_expr/3, pos_to_fun_def/2, pos_to_var_name/2.

+ +

pos_to_node/3

+
+

pos_to_node(FileOrTree::filename() | syntaxTree(), Pos::pos(), Cond::function()) -> {ok, syntaxTree()} | {error, string()}

+

Returns the outmost Node which encloses the cursor and + makes Pred(Node) return true.

+ +

pos_to_var/2

+
+

pos_to_var(Node::syntaxTree(), Pos::pos()) -> {ok, syntaxTree()} | {error, string()}

+

Returns the variable node at position Pos.

+ +

pos_to_var_name/2

+
+

pos_to_var_name(Node::syntaxTree(), Pos::{integer(), integer()}) -> {ok, {VarName, DefPos}} | {error, string()} +

+

Returns the variable name that occurs at the position specified by position Pos.

+

See also: pos_to_expr/3, pos_to_fun_def/2, pos_to_fun_name/2.

+ +

range_to_node/3

+
+

range_to_node(FileOrTree::filename() | syntaxTree(), Range::{pos(), pos()}, Cond::Pred) -> syntaxTree() | {error, string()}

+

Returns the largest, left-most Node which is enclosed by the location range specified, + and also makes Pred(Node) return true.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:21.

+ + diff --git a/docs/doc/api_refac.html b/docs/doc/api_refac.html new file mode 100644 index 00000000..410f0afc --- /dev/null +++ b/docs/doc/api_refac.html @@ -0,0 +1,719 @@ + + + + +Module api_refac + + + + +
+ +

Module api_refac

+ +This module defines the API exposed by Wrangler for users to compose +refactorings or code inspectors that meet their own needs. + +

Authors: Huiqing Li (H.Li@kent.ac.uk).

+ +

Description

+This module defines the API exposed by Wrangler for users to compose +refactorings or code inspectors that meet their own needs. A refactoring +consists of two parts: program analysis and program transformation, both +of which involve various AST traversals and manipulations, and require +deep knowledge of the AST representation details. To make the processing +of writing a refactoring easier, we have extended Wrangler with a framework +that allows users to define refactorings or code inspectors in an intuitive +and concise way. With this framework, user-defined refactorings are no +second-class refactorings. Like the existing refactorings supported by Wrangler, +user-defined refactoring can also be invoked from the refactoring menu, and +also benefit the existing features such as preview of refactoring results, +layout preservation, selective refactoring, undo of refactorings, etc, for free.

+ +

The user-extensibility of Wrangler is achieved by introducing a new layer on top + of the existing low-level API which provides direct access to the details of syntactic + and semantic representation of the Erlang language. We call the new layer the + Wrangler API. The Wrangler API consists of three parts:

+ +

-- A template and rule based program analysis and transformation framework that +allows users to express their analysis and transformation in an intuitive and +concise way without diving into the details of internal program representation +used by the refactoring tool;

+ +

-- A generic behaviour especially for refactoring encapsulates the generic parts + that are common to all refactorings, while the user only has to provide the + parts that are specific to the refactoring under consideration. See gen_refac.

+ +

-- A collection of API functions, such as API functions for abstract syntax tree + traversal, API functions for retrieving context information from AST nodes, API + functions for mapping the textual selection of program source to its internal + representation (see api_interface), etc.

+ + Here are some macros that can be used to expression transformation rules and/or + information collectors: + + Some example refactorings implemented using the Wrangler API: + +

Function Index

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
add_to_export_after/3Adds an entity FAtoAdd to the export list of an export attribute + right after another entity FA; if FA is none then append + the new entity to the end of the export list.
bound_var_names/1Returns all the variable names that are declared within Node.
bound_vars/1Returns all the variables, including both variable name and define + location, that are declared within Node.
client_files/2Returns those files, included in SearchPaths, which use/import + some of the functions defined in File.
defined_funs/1Returns all the functions that are defined by an Erlang file.
env_var_names/1Returns all the variable names that are visible to Node.
env_vars/1Returns all the variables, including both variable name and + define location, that are visible to Node.
exported_funs/1Returns all the functions that are exported by an Erlang file.
exported_var_names/1Returns all the variable names that are declared within Node, and + also used by the code outside Node.
exported_vars/1Returns all the variables, including both variable name and define + location, that are declared within Node, and also used by the + code outside Node.
free_var_names/1Returns all the variable names that are free within Node.
free_vars/1Returns all the variables, including both variable name and define + location, that are free within Node.
fun_define_info/1Returns the MFA information attached a node that represents a + function name or a qualified function name.
get_app_args/1For a function application node that matches ?FUN_APPY(M,F,A), + get the part that represents the arguments to which the function F + is applied.
get_app_fun/1For a function application node that matches ?FUN_APPY(M,F,A), + get the part that represents the function name.
get_app_mod/1For a function application node that matches ?FUN_APPLY(M,F,A), + get the part that represents the module name if M appears in + the application; otherwise returns none.
get_ast/1Returns the AST representation of an Erlang file.
get_module_info/1Returns the module-level information about the Erlang file.
imported_funs/1Returns all the functions that are (auto)imported by an Erlang file.
imported_funs/2Returns all the functions that are imported from ModuleName by an Erlang file.
inscope_funs/1Returns all the functions that are in-scope in the current module.
insert_an_attr/2Inserts an attribute before the first function definition.
is_attribute/2Returns true if Node represents an attribute + of name Name.
is_behaviour_instance_of/2Returns true if the Erlang module + defined in File is a behaviour instance of the module Mod.
is_exported/2Returns true if {FunName, Arity} is exported by the Erlang module + defined in File.
is_expr/1Returns true if Node represents an expression (either a general + expression or a guard expression), otherwise false.
is_fun_name/1Returns true if a string is lexically a legal function name, + otherwise false.
is_guard_expr/1Returns true if Node represents a guard expression, otherwise false.
is_import/2Returns true if Node represents an import attribute that + imports module ModName
is_pattern/1Returns true if Node represents a pattern, otherwise false.
is_var_name/1Returns true if a string is lexically a legal variable name, + otherwise false.
make_new_name/2Generates a new name by appending "_1" to the end of the 'BaseName' + until the new name is not a member of UsedNames.
mfa_to_fun_def/2Returns the function form that defines MFA; none is returns if no + such function definition found.
module_name/1Returns the name of the module defined in File,.
remove_from_import/2Removes F/A from the entity list of the import attribute + represented by Node.
start_end_loc/1Returns the start and end locations of the code represented + by Tree in the source file.
syntax_category/1Returns the syntax category of Node.
syntax_context/1Returns the syntax context of Node.
type/1The function is the same as erl_syntax:type/1.
update_app_args/2Replaces the arguments of a function application node with Args.
update_app_fun/2Replaces the function name part of a function application node with FunName.
update_app_mod/2Replaces the module name part of a function application node with Modname.
var_refs/1Returns all the locations where a variable is used, not including + the locations where the variable is bound, when Node represents + a variable, otherwise returns an empty list.
variable_define_pos/1Returns the define location of the variable represented by Node; + [{0,0}] is returned is the variable is a free variable or Node is + not properly annotated.
+ +

Function Details

+ +

add_to_export_after/3

+
+

add_to_export_after(Node::attribute(), FAtoAdd::{function(), arity()}, FA::{function(), arity()} | none) -> attribute()

+

Adds an entity FAtoAdd to the export list of an export attribute + right after another entity FA; if FA is none then append + the new entity to the end of the export list.

+ +

bound_var_names/1

+
+

bound_var_names(Node::[syntaxTree()] | syntaxTree()) -> [atom()]

+

Returns all the variable names that are declared within Node.

+ +

bound_vars/1

+
+

bound_vars(Node::[syntaxTree()] | syntaxTree()) -> [{atom(), pos()}]

+

Returns all the variables, including both variable name and define + location, that are declared within Node.

+ +

client_files/2

+
+

client_files(File::filename(), SearchPaths::[filename() | dir()]) -> [filename()]

+

Returns those files, included in SearchPaths, which use/import + some of the functions defined in File.

+ +

defined_funs/1

+
+

defined_funs(File::filename()) -> [{atom(), integer()}]

+

Returns all the functions that are defined by an Erlang file.

+ +

env_var_names/1

+
+

env_var_names(Node::syntaxTree()) -> [atom()]

+

Returns all the variable names that are visible to Node.

+ +

env_vars/1

+
+

env_vars(Node::syntaxTree()) -> [{atom(), pos()}]

+

Returns all the variables, including both variable name and + define location, that are visible to Node.

+ +

exported_funs/1

+
+

exported_funs(File::filename()) -> [{atom(), integer()}]

+

Returns all the functions that are exported by an Erlang file.

+ +

exported_var_names/1

+
+

exported_var_names(Node::[syntaxTree()] | syntaxTree()) -> [atom()]

+

Returns all the variable names that are declared within Node, and + also used by the code outside Node.

+ +

exported_vars/1

+
+

exported_vars(Nodes::[syntaxTree()] | syntaxTree()) -> [{atom(), pos()}]

+

Returns all the variables, including both variable name and define + location, that are declared within Node, and also used by the + code outside Node.

+ +

free_var_names/1

+
+

free_var_names(Node::[syntaxTree()] | syntaxTree()) -> [atom()]

+

Returns all the variable names that are free within Node.

+ +

free_vars/1

+
+

free_vars(Node::[syntaxTree()] | syntaxTree()) -> [{atom(), pos()}]

+

Returns all the variables, including both variable name and define + location, that are free within Node.

+ +

fun_define_info/1

+
+

fun_define_info(Node::syntaxTree()) -> {modulename(), functionname(), arity()} | unknown

+

Returns the MFA information attached a node that represents a + function name or a qualified function name. unknown is returned is + no MFA information is annotated to this node or Node does not + represent a function name.

+ +

get_app_args/1

+
+

get_app_args(AppNode::syntaxTree()) -> [syntaxTree()] | syntaxTree()

+

For a function application node that matches ?FUN_APPY(M,F,A), + get the part that represents the arguments to which the function F + is applied. This function returns the arguments as a list of AST + nodes if the the function application matches one of those templates" + with Args@@, as specified in the documentation of ?FUN_APPY(M,F,A); + otherwise a single AST node.

+ +

get_app_fun/1

+
+

get_app_fun(AppNode::syntaxTree()) -> syntaxTree()

+

For a function application node that matches ?FUN_APPY(M,F,A), + get the part that represents the function name.

+ +

get_app_mod/1

+
+

get_app_mod(AppNode::syntaxTree()) -> syntaxTree() | none

+

For a function application node that matches ?FUN_APPLY(M,F,A), + get the part that represents the module name if M appears in + the application; otherwise returns none.

+ +

get_ast/1

+
+

get_ast(File::filename()) -> syntaxTree() | {error, errorInfo()}

+

Returns the AST representation of an Erlang file.

+ +

get_module_info/1

+
+

get_module_info(File::filename()) -> {ok, module_info()}

+

Returns the module-level information about the Erlang file.

+ +

imported_funs/1

+
+

imported_funs(File::filename()) -> [{modulename(), functionname(), integer()}]

+

Returns all the functions that are (auto)imported by an Erlang file.

+ +

imported_funs/2

+
+

imported_funs(File::filename(), ModuleName::modulename()) -> [{functionname(), integer()}]

+

Returns all the functions that are imported from ModuleName by an Erlang file.

+ +

inscope_funs/1

+
+

inscope_funs(FileOrModInfo::filename() | module_info()) -> [{atom(), atom(), integer()}]

+

Returns all the functions that are in-scope in the current module. + An in-scope function could be an (auto-)imported function, or a + function that is defined in the current module.

+ +

insert_an_attr/2

+
+

insert_an_attr(AST::syntaxTree(), Attr::attribute()) -> syntaxTree()

+

Inserts an attribute before the first function definition.

+ +

is_attribute/2

+
+

is_attribute(Node::syntaxTree(), Name::atom()) -> boolean()

+

Returns true if Node represents an attribute + of name Name.

+ +

is_behaviour_instance_of/2

+
+

is_behaviour_instance_of(Mod::atom(), File::string()) -> boolean()

+

Returns true if the Erlang module + defined in File is a behaviour instance of the module Mod.

+ +

is_exported/2

+
+

is_exported(X1::{atom(), integer()}, FileOrModInfo::filename()) -> boolean()

+

Returns true if {FunName, Arity} is exported by the Erlang module + defined in File.

+ +

is_expr/1

+
+

is_expr(Node::syntaxTree()) -> boolean()

+

Returns true if Node represents an expression (either a general + expression or a guard expression), otherwise false.

+ +

is_fun_name/1

+
+

is_fun_name(Name::string()) -> boolean()

+

Returns true if a string is lexically a legal function name, + otherwise false.

+ +

is_guard_expr/1

+
+

is_guard_expr(Node::syntaxTree()) -> boolean()

+

Returns true if Node represents a guard expression, otherwise false.

+ +

is_import/2

+
+

is_import(Node::syntaxTree(), ModName::atom()) -> boolean()

+

Returns true if Node represents an import attribute that + imports module ModName

+ +

is_pattern/1

+
+

is_pattern(Node::syntaxTree()) -> boolean()

+

Returns true if Node represents a pattern, otherwise false.

+ +

is_var_name/1

+
+

is_var_name(Name::string()) -> boolean()

+

Returns true if a string is lexically a legal variable name, + otherwise false.

+ +

make_new_name/2

+
+

make_new_name(BaseName::atom(), UsedNames::[atom()]) -> atom()

+

Generates a new name by appending "_1" to the end of the 'BaseName' + until the new name is not a member of UsedNames.

+ +

mfa_to_fun_def/2

+
+

mfa_to_fun_def(File::filename(), MFA::mfa()) -> syntaxTree() | none

+

Returns the function form that defines MFA; none is returns if no + such function definition found.

+ +

module_name/1

+
+

module_name(File::filename()) -> {ok, modulename()} | {error, any()}

+

Returns the name of the module defined in File,

+ +

remove_from_import/2

+
+

remove_from_import(Node::attribute(), FA::{functionname(), arity()}) -> attribute()

+

Removes F/A from the entity list of the import attribute + represented by Node.

+ +

start_end_loc/1

+
+

start_end_loc(Tree::[syntaxTree()] | syntaxTree()) -> {pos(), pos()}

+

Returns the start and end locations of the code represented + by Tree in the source file.

+ +

syntax_category/1

+
+

syntax_category(Node::syntaxTree()) -> pattern | expression | guard_expression | unknown

+

Returns the syntax category of Node.

+ +

syntax_context/1

+
+

syntax_context(Node::syntaxTree()) -> atom()

+

Returns the syntax context of Node.

+ +

type/1

+
+

type(Node::syntaxTree()) -> atom()

+

The function is the same as erl_syntax:type/1. It returns the + type tag of Node. If Node + does not represent a syntax tree, evaluation fails with reason + badarg. Node types currently defined are: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
applicationarity_qualifieratomattribute
binarybinary_fieldblock_exprcase_expr
catch_exprcharclass_qualifierclause
commentcond_exprconjunctiondisjunction
eof_markererror_markerfloatform_list
fun_exprfunctiongeneratorif_expr
implicit_funinfix_exprintegerlist
list_compmacromatch_exprmodule_qualifier
niloperatorparenthesesprefix_expr
qualified_namequery_exprreceive_exprrecord_access
record_exprrecord_fieldrecord_index_exprrule
size_qualifierstringtexttry_expr
tupleunderscorevariablewarning_marker

+ +

update_app_args/2

+
+

update_app_args(AppNode::syntaxTree(), Args::[syntaxTree()] | syntaxTree()) -> syntaxTree()

+

Replaces the arguments of a function application node with Args. + The node AppNode should match one of the templates specified ?FUN_APPY(M,F,A).

+ +

update_app_fun/2

+
+

update_app_fun(AppNode::syntaxTree(), FunName::syntaxTree()) -> syntaxTree()

+

Replaces the function name part of a function application node with FunName. + The node AppNode should match one of the templates specified ?FUN_APPY(M,F,A).

+ +

update_app_mod/2

+
+

update_app_mod(AppNode::syntaxTree(), ModName::syntaxTree()) -> syntaxTree()

+

Replaces the module name part of a function application node with Modname. + The node AppNode should match one of the templates specified by?FUN_APPY(M,F,A).

+ +

var_refs/1

+
+

var_refs(Node::syntaxTree()) -> [pos()]

+

Returns all the locations where a variable is used, not including + the locations where the variable is bound, when Node represents + a variable, otherwise returns an empty list.

+ +

variable_define_pos/1

+
+

variable_define_pos(Node::syntaxTree()) -> [pos()]

+

Returns the define location of the variable represented by Node; + [{0,0}] is returned is the variable is a free variable or Node is + not properly annotated.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:22.

+ + diff --git a/docs/doc/api_wrangler.html b/docs/doc/api_wrangler.html new file mode 100644 index 00000000..ae3041ad --- /dev/null +++ b/docs/doc/api_wrangler.html @@ -0,0 +1,112 @@ + + + + +Module api_wrangler + + + + +
+ +

Module api_wrangler

+This module describes the refactoring commands that can be run in an Erlang shell. +

Copyright © 2006-2011 Huiqing Li, Simon Thompson +

+ +

Authors: Huiqing Li, Simon Thompson [web site: http://www.cs.kent.ac.uk/projects/wrangler].

+ +

Description

This module describes the refactoring commands that can be run in an Erlang shell. +

All refactorings commands should be run in the context of a Wrangler application. + Use api_wrangler:start() to start a Wrangler application, and api_wrangler:stop() to stop the + application. +

+

Function Index

+ + + + + + + + + +
copy_mod/3Copy a module.
move_fun/5Move a function to another module.
refac_bug_cond/1For QuickCheck only.
rename_fun/5Rename a function.
rename_mod/3Rename a module.
similar_code/7Similar code detection.
start/0Start a Wrangler application.
stop/0Stop a Wrangler application.
undo/0Undo the previous refactoring.
+ +

Function Details

+ +

copy_mod/3

+
+

copy_mod(ModOrFileName::modulename() | filename(), NewModName::modulename(), SearchPaths::[dir()]) -> {ok, FilesChanged::[filename()]} | {error, Reason}

+

Copy a module. +

This refactoring affects all those modules in which the module name is used, + and returns either ok with the list of files affected by this + refactoring, or an error message.

+ +

move_fun/5

+
+

move_fun(FromModOrFileName::modulename() | filename(), FunName::atom(), Arity::integer(), ToModOrFileName::modulename() | filename(), SearchPaths::[dir()]) -> {ok, FilesChanged::[filename()]} | {error, Reason}

+

Move a function to another module. +

This refactoring moves the function specified, together with functions that are only used + by the function to be moved, to the target module. This refactorings affects all those + modules in which the function to be moved is used, and returns either ok with the list of + files affected by this refactoring, or an error message. +

+ +

refac_bug_cond/1

+
+

refac_bug_cond(DirOrFileList::[filename() | dir()]) -> {ok, string()} | {error, term()}

+

For QuickCheck only.

+ +

rename_fun/5

+
+

rename_fun(ModOrFileName::modulename() | filename(), FunName::atom(), Arity::integer(), NewFunName::atom(), SearchPaths::[dir()]) -> {ok, FilesChanged::[filename()]} | {error, Reason}

+

Rename a function. +

This refactoring affects all those modules in which the function renamed is + used, and returns either ok with the list of files affected by this + refactoring, or an error message. +

+ +

rename_mod/3

+
+

rename_mod(ModorFileName::modulename() | filename(), NewModName::modulename(), SearchPaths::[dir()]) -> {ok, FilesChanged::[filename()]} | {error, Reason}

+

Rename a module. +

This refactoring affects all those modules in which the module name is used, + and returns either ok with the list of files affected by this + refactoring, or an error message.

+ +

similar_code/7

+
+

similar_code(DirFileList::[filename() | dir()], MinLen::integer(), MinToks::integer(), MinFreq::integer(), MaxVars::integer(), SimiScore::float(), SearchPaths::[dir()]) -> {ok, string()} | {error, Reason}

+

Similar code detection. +

A similar code detector which takes an Erlang project (or just a collection of Erlang files) and + a set of parameters as input, performs clone detection, and reports the clone classes found. + Five parameters, which are of a conjunction relation, can be specified so that the user can + have control of the granularity of the clone classes reported. These parameters are:
+ MinLen: the minimum number of expressions included in a code clone which is a sequence of expressions;
+ MinToks: the minimum number of tokens included in a code clone (minimum value: 20);
+ MinFreq: the minimum number of duplications of a cloned code fragment (minimum value: 2);
+ MaxVars: the maximum number of new parameters of the least-general common abstraction function;
+ SimiScore: the similarity score threshold which is between 0.1 and 1.0. +

+ +

start/0

+
+

start() -> {ok, Pid} | {error, Reason}

+

Start a Wrangler application.

+ +

stop/0

+
+

stop() -> ok

+

Stop a Wrangler application.

+ +

undo/0

+
+

undo() -> {ok, FilesChanged::[filename()]} | {error, Reason}

+

Undo the previous refactoring. This only works within a Wrangler application.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:22.

+ + diff --git a/docs/doc/behaviour_extraction/ast_tree.html b/docs/doc/behaviour_extraction/ast_tree.html new file mode 100644 index 00000000..687a8223 --- /dev/null +++ b/docs/doc/behaviour_extraction/ast_tree.html @@ -0,0 +1,274 @@ + + + + +Module ast_tree + + + + +
+ +

Module ast_tree

+ + Implements functions to convert between Wrangler AST and tree. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Implements functions to convert between Wrangler AST and tree +

Function Index

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
ast_to_tree/5 + Transforms a Syntax Tree into a tree with isolated nodes for + easier manipulation.
breaks_funname/2 + Returns true if separating Node from ParentNode (assuming ParentNode is the parent node of Node), + would separate a function call (in some form) from the indicator of the name/arity/module of + the destination function.
get_file_name/1 + Gets the filename from the tree metadata record.
get_fun_name/2 + If the node represents a function it returns a tuple with the + name of the function as a string and the arity as a number.
get_inscope_funs/1 + Gets the list of functions in scope from the tree metadata record.
get_left_if_node_pair/1 + Returns the left node if it is a node pair.
get_macro_info/1 + Parses the AST in Tree in order to extract information about the macros defined and + used.
get_macros_list/1 + Gets a list of the AST blocks containing macros and information about + the macros, records, and imports provided by them.
get_module_info/1 + Gets the module info from the tree metadata record.
get_placeholders_from_node/1 + Extracts placeholders from the node.
get_right_if_node_pair/1 + Returns the right node if it is a node pair.
get_search_paths/1 + Gets the list of paths in the search path from the tree metadata record.
get_tab_width/1 + Gets the tab width from the tree metadata record.
is_a_function/1 + It returns true if the node represents a function, otherwise + it returns false.
is_expression_or_function/1 + Checks the category of the Node and returns true if it is + "expression" or if the node is a function declaration.
is_function_or_macro/1 + Returns true if the node is a macro of a function application, + (for both its alternatives).
reparse/1 + Reparses the AST in Tree to renew its information (like attributes).
replace_in_node/2 + Replaces the list of nodes Replacements in the subtrees of Node.
set_file_name/2 + Sets the filename in the tree metadata record.
set_inscope_funs/2 + Sets the list of functions in scope in the tree metadata record.
set_module_info/2 + Sets the module info in the tree metadata record.
set_search_paths/2 + Sets the list of paths in the search path in the tree metadata record.
set_tab_width/2 + Sets the tab width in the tree metadata record.
show_node/1 + Transforms a node or node pair into a compact representation for debugging.
tree_to_ast/1 + Extracts an AST from a Tree that contains an AST.
tree_to_ast/2 + Extracts an AST from a Tree that contains an AST, taking Node as the root node.
value/1 + Returns a "semantic" representation of the node, (which is used for + comparing two nodes and decide if they can be mergerd).
+ +

Function Details

+ +

ast_to_tree/5

+
+

ast_to_tree(AST::wrangler_syntax:syntaxTree(), FileName::string(), ModuleInfo::[{atom(), term()}], SearchPaths::[string()], TabWidth::integer()) -> tree:tree()

+

+ Transforms a Syntax Tree into a tree with isolated nodes for + easier manipulation.

+ +

breaks_funname/2

+
+

breaks_funname(NodePair::tree:tree_node(), ParentNode::tree:tree_node()) -> boolean()

+

+ Returns true if separating Node from ParentNode (assuming ParentNode is the parent node of Node), + would separate a function call (in some form) from the indicator of the name/arity/module of + the destination function.

+ +

get_file_name/1

+
+

get_file_name(Tree::tree:tree()) -> string()

+

+ Gets the filename from the tree metadata record.

+ +

get_fun_name/2

+
+

get_fun_name(Node::tree:tree_node(), Tree::tree:tree()) -> {ok, {string(), non_neg_integer()}} | error

+

+ If the node represents a function it returns a tuple with the + name of the function as a string and the arity as a number. + The Tree must match the node if exclusive or be the left tree + if common.

+ +

get_inscope_funs/1

+
+

get_inscope_funs(Tree::tree:tree()) -> [{atom(), atom(), integer()}]

+

+ Gets the list of functions in scope from the tree metadata record.

+ +

get_left_if_node_pair/1

+
+

get_left_if_node_pair(Node::tree:tree_node()) -> tree:tree_node()

+

+ Returns the left node if it is a node pair.

+ +

get_macro_info/1

+
+

get_macro_info(Tree::tree:tree()) -> {[{wrangler_syntax:syntaxTree(), term()}], [term()]}

+

+ Parses the AST in Tree in order to extract information about the macros defined and + used. It returns the macro information gathered by wrangler_epp:parse_file/5.

+ +

get_macros_list/1

+
+

get_macros_list(Tree::tree:tree()) -> [{MacroAST::wrangler_syntax:syntaxTree(), MacroInfo::[term()]}]

+

+ Gets a list of the AST blocks containing macros and information about + the macros, records, and imports provided by them.

+ +

get_module_info/1

+
+

get_module_info(Tree::tree:tree()) -> [{atom(), term()}]

+

+ Gets the module info from the tree metadata record.

+ +

get_placeholders_from_node/1

+
+

get_placeholders_from_node(Nodes::Node) -> [PH] +

+

+ Extracts placeholders from the node. It may be a node pair or + a simple node. If it is a node pair it uses the left alternative. + It uses the wrangler_tools to accumulate them.

+ +

get_right_if_node_pair/1

+
+

get_right_if_node_pair(Node::tree:tree_node()) -> tree:tree_node()

+

+ Returns the right node if it is a node pair.

+ +

get_search_paths/1

+
+

get_search_paths(Tree::tree:tree()) -> [string()]

+

+ Gets the list of paths in the search path from the tree metadata record.

+ +

get_tab_width/1

+
+

get_tab_width(Tree::tree:tree()) -> integer()

+

+ Gets the tab width from the tree metadata record.

+ +

is_a_function/1

+
+

is_a_function(Node::tree:tree_node()) -> boolean()

+

+ It returns true if the node represents a function, otherwise + it returns false.

+ +

is_expression_or_function/1

+
+

is_expression_or_function(Node::tree:tree_node()) -> boolean()

+

+ Checks the category of the Node and returns true if it is + "expression" or if the node is a function declaration. + It returns false otherwise.

+ +

is_function_or_macro/1

+
+

is_function_or_macro(Node::tree:tree_node()) -> boolean()

+

+ Returns true if the node is a macro of a function application, + (for both its alternatives).

+ +

reparse/1

+
+

reparse(Tree::tree:tree()) -> tree:tree()

+

+ Reparses the AST in Tree to renew its information (like attributes). It + copies the node properties stored in the previous node. It requires that + the AST topology before and after reparsing is the same.

+ +

replace_in_node/2

+
+

replace_in_node(Replacements::[wrangler_syntax:syntaxTree()], Node::wrangler_syntax:syntaxTree()) -> wrangler_syntax:syntaxTree()

+

+ Replaces the list of nodes Replacements in the subtrees of Node.

+ +

set_file_name/2

+
+

set_file_name(FileName::string(), Tree::tree:tree()) -> tree:tree()

+

+ Sets the filename in the tree metadata record.

+ +

set_inscope_funs/2

+
+

set_inscope_funs(InscopeFuns::[{atom(), atom(), integer()}], Tree::tree:tree()) -> tree:tree()

+

+ Sets the list of functions in scope in the tree metadata record.

+ +

set_module_info/2

+
+

set_module_info(ModuleInfo::[{atom(), term()}], Tree::tree:tree()) -> tree:tree()

+

+ Sets the module info in the tree metadata record.

+ +

set_search_paths/2

+
+

set_search_paths(SearchPaths::[string()], Tree::tree:tree()) -> tree:tree()

+

+ Sets the list of paths in the search path in the tree metadata record.

+ +

set_tab_width/2

+
+

set_tab_width(TabWidth::integer(), Tree::tree:tree()) -> tree:tree()

+

+ Sets the tab width in the tree metadata record.

+ +

show_node/1

+
+

show_node(Node::tree:tree_node()) -> {{node, tree:tree_ph()} | {node_pair, tree:tree_ph(), tree:tree_ph()}, any()}

+

+ Transforms a node or node pair into a compact representation for debugging.

+ +

tree_to_ast/1

+
+

tree_to_ast(Tree::tree:tree()) -> AST::wrangler_syntax:syntaxTree()

+

+ Extracts an AST from a Tree that contains an AST.

+ +

tree_to_ast/2

+
+

tree_to_ast(Node::tree:tree_node(), Tree::tree:tree()) -> wrangler_syntax:syntaxTree()

+

+ Extracts an AST from a Tree that contains an AST, taking Node as the root node.

+ +

value/1

+
+

value(Node::tree:tree_node()) -> any()

+

+ Returns a "semantic" representation of the node, (which is used for + comparing two nodes and decide if they can be mergerd).

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/cluster.html b/docs/doc/behaviour_extraction/cluster.html new file mode 100644 index 00000000..bdc69005 --- /dev/null +++ b/docs/doc/behaviour_extraction/cluster.html @@ -0,0 +1,149 @@ + + + + +Module cluster + + + + +
+ +

Module cluster

+ + Implements a cluster of nodes. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Implements a cluster of nodes. The clusters save information about + which parent-child relationships between its nodes. Clusters are + assumed to have tree hierarchy (no loops), and, as such, a single + root. +

Data Types

+ +

cluster()

+

abstract datatype: cluster(NodeType)

+ + +

Function Index

+ + + + + + + + + + + + +
get_nodes/1 + Returns a set with all the nodes in the Cluster.
get_root/1 + Returns the root node of the Cluster.
has_node/2 + Returns a boolean that indicates whether the Cluster contains the Node.
is_indirection_cluster/1 + Returns whether the cluster is an indirection "fake" cluster or not.
make_indirection_cluster/0 + Creates an indirection "fake" cluster.
merge_clusters/2 + Takes two clusters and returns a new cluster containing all the nodes or the + atom disjoint if they have no common nodes.
new_cluster/1 + Creates a cluster with a single node.
new_parent_child_to_cluster/2 + Creates a cluster with a Node and its ParentNode.
remove_split/2 + Removes the Node from the Cluster an returns the resulting subclusters created, + (those that were hold together by the removed node).
show_cluster/1 + Returns a more readable version of custers.
show_cluster/2 + Returns a more readable version of custers and takes a function + that is suppoused to make the nodes in the clusters more readable.
size/1 + Returns the number of nodes that the cluster has.
+ +

Function Details

+ +

get_nodes/1

+
+

get_nodes(Cluster::cluster(NodeType)) -> [NodeType]

+

+ Returns a set with all the nodes in the Cluster.

+ +

get_root/1

+
+

get_root(Cluster::cluster(NodeType)) -> OutNode::NodeType

+

+ Returns the root node of the Cluster.

+ +

has_node/2

+
+

has_node(Node::NodeType, Cluster::cluster(NodeType)) -> boolean() +

+

+ Returns a boolean that indicates whether the Cluster contains the Node.

+ +

is_indirection_cluster/1

+
+

is_indirection_cluster(X1::cluster(term())) -> false | {true, reference()}

+

+ Returns whether the cluster is an indirection "fake" cluster or not.

+ +

make_indirection_cluster/0

+
+

make_indirection_cluster() -> {reference(), cluster(term())}

+

+ Creates an indirection "fake" cluster.

+ +

merge_clusters/2

+
+

merge_clusters(Cluster::cluster(Node), X2::cluster(Node)) -> {ok, cluster(Node)} | disjoint

+

+ Takes two clusters and returns a new cluster containing all the nodes or the + atom disjoint if they have no common nodes. It assumes that the clusters + contain subtrees that belong to global tree, and, as such, nor the individual + clusters nor the result cluster should contain any loops, and no node should + have several parents.

+ +

new_cluster/1

+
+

new_cluster(Node::NodeType) -> cluster(NodeType)

+

+ Creates a cluster with a single node.

+ +

new_parent_child_to_cluster/2

+
+

new_parent_child_to_cluster(Node::N, Node::N) -> cluster(N) +

+

+ Creates a cluster with a Node and its ParentNode.

+ +

remove_split/2

+
+

remove_split(Node::NodeType, Cluster::cluster(NodeType)) -> [cluster(NodeType)]

+

+ Removes the Node from the Cluster an returns the resulting subclusters created, + (those that were hold together by the removed node).

+ +

show_cluster/1

+
+

show_cluster(Clus::cluster(term())) -> #{}

+

+ Returns a more readable version of custers. This is done by + transforming dicts and sets into lists.

+ +

show_cluster/2

+
+

show_cluster(Fun::fun((NodeType) -> any()), Cluster::cluster(NodeType)) -> #{}

+

+ Returns a more readable version of custers and takes a function + that is suppoused to make the nodes in the clusters more readable. + This is done by transforming dicts and sets into lists and by + applying the supplied function to the nodes.

+ +

size/1

+
+

size(Cluster::cluster(term())) -> non_neg_integer()

+

+ Returns the number of nodes that the cluster has.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/cluster_dict.html b/docs/doc/behaviour_extraction/cluster_dict.html new file mode 100644 index 00000000..3765abcf --- /dev/null +++ b/docs/doc/behaviour_extraction/cluster_dict.html @@ -0,0 +1,109 @@ + + + + +Module cluster_dict + + + + +
+ +

Module cluster_dict

+ + Implements a data type that congregates and manages clusters of + nodes. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Implements a data type that congregates and manages clusters of + nodes. It relies on the internal data type cluster. +

Data Types

+ +

cluster_dict()

+

abstract datatype: cluster_dict(Node)

+ + +

Function Index

+ + + + + + + +
extract_trivial_clusters/1 + Removes clusters with only one node from the cluster dictionary.
get_cluster_for_node/2 + Finds the cluster that has the Node in the ClusterDict.
growing_map_fold/3 + Mapfolds a function through a clusters dictionary.
merge_cluster/2 + Adds a Cluster to the ClusterDict and merges the new Cluster with + the clusters with common nodes in ClusterDict.
new/0 + Creates a new empty cluster dictionary.
show_cluster_dict/1 + Returns a more readable version of custer dictionaries.
show_cluster_dict/2 + Returns a more readable version of custer dictionaries and takes + a function that is suppoused to make the nodes in the clusters + more readable.
+ +

Function Details

+ +

extract_trivial_clusters/1

+
+

extract_trivial_clusters(Cluster_dict::cluster_dict(NodeType)) -> {[cluster:cluster(NodeType)], cluster_dict(NodeType)}

+

+ Removes clusters with only one node from the cluster dictionary. + It returns a list with the removed clusters.

+ +

get_cluster_for_node/2

+
+

get_cluster_for_node(Node::N, Cluster_dict::cluster_dict(N)) -> {ok, Cluster::cluster:cluster(N)} | error

+

+ Finds the cluster that has the Node in the ClusterDict.

+ +

growing_map_fold/3

+
+

growing_map_fold(Fun::fun((cluster:cluster(N), Acc) -> {[cluster:cluster(N)], none | cluster:cluster(N), Acc}), Acc, Cluster_dict::cluster_dict(N)) -> {cluster_dict(N), Acc}

+

+ Mapfolds a function through a clusters dictionary. As opposed to the + traditional mapfold, this one expects an extra element in the + returned tuple, (the first one), which specifies which new clusters + must be map_folded later, (in addition to the original ones + from the cluster dictionary). The updated cluster (second element of + the tuple returned by the function), can be the atom none, this + means that the Cluster will not be in the resulting list.

+ +

merge_cluster/2

+
+

merge_cluster(Cluster::cluster:cluster(N), ClusterDict::cluster_dict(N)) -> cluster_dict(N)

+

+ Adds a Cluster to the ClusterDict and merges the new Cluster with + the clusters with common nodes in ClusterDict.

+ +

new/0

+
+

new() -> cluster_dict(any())

+

+ Creates a new empty cluster dictionary.

+ +

show_cluster_dict/1

+
+

show_cluster_dict(Clus::cluster_dict(term())) -> #{}

+

+ Returns a more readable version of custer dictionaries. This + is done by transforming dicts and sets into lists.

+ +

show_cluster_dict/2

+
+

show_cluster_dict(Fun::fun((NodeType) -> any()), Cluster_dict::cluster_dict(NodeType)) -> #{}

+

+ Returns a more readable version of custer dictionaries and takes + a function that is suppoused to make the nodes in the clusters + more readable. This is done by transforming dicts and sets into + lists and by applying the supplied function to the nodes.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:18.

+ + diff --git a/docs/doc/behaviour_extraction/cluster_folding.html b/docs/doc/behaviour_extraction/cluster_folding.html new file mode 100644 index 00000000..e345b307 --- /dev/null +++ b/docs/doc/behaviour_extraction/cluster_folding.html @@ -0,0 +1,301 @@ + + + + +Module cluster_folding + + + + +
+ +

Module cluster_folding

+ + Implements the functionality to traverse the clusters frontiers + in roughly breadth first order. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Implements the functionality to traverse the clusters frontiers + in roughly breadth first order. +

Data Types

+ +

acc()

+

acc() = #acc{cluster_labels = da_map:da_map({comm | {ex, 1 | 2}, string()}, cluster:cluster(tree:tree_node())), exp_funs = sets:set({atom(), integer()})}

+

Record for use as accumulator when folding through cluster borders. + Contains the following fields:

+ +

cluster_counters()

+

cluster_counters() = #cluster_counters{}

+

Record that keeps counters used for naming + functions and ordering them in the files. + Contains the following fields:

+ +

cluster_dicts()

+

cluster_dicts() = #cluster_dicts{comm_clus = cluster_dict:cluster_dict(tree:tree_node()), ex_clus1 = cluster_dict:cluster_dict(tree:tree_node()), ex_clus2 = cluster_dict:cluster_dict(tree:tree_node())}

+

Record for keeping the updated cluster dictionaries. + Contains the following fields:

+ +

cluster_info()

+

cluster_info() = #cluster_info{}

+

Record for keeping information about a particular + cluster. Contains the following fields:

+ +

environment_info()

+

environment_info() = #environment_info{}

+

Record that contains environment information + like the free and bound variables at the root + of a cluster. Contains the following fields:

+ +

tree_info()

+

tree_info() = #tree_info{tree1 = tree:tree(), tree2 = tree:tree(), tree1_args = dict:dict({FunName::string(), Arity::non_neg_integer()}, [ArgName::string()]), tree2_args = dict:dict({FunName::string(), Arity::non_neg_integer()}, [ArgName::string()]), mapping = da_map:da_map(tree:tree_node(), tree:tree_node())}

+

Record for keeping the tree and mapping information. + Contains the following fields:

+ +

Function Index

+ + + + + + + + + + + + +
find_actual_exported_vars_for_asym_label/3 + Gets the exported variables for the top node of the cluster linked to AsymLabel, + considering only the tree specified by Pos.
find_actual_free_vars_for_asym_label/3 + Gets the free variables for the top node of the cluster linked to AsymLabel, + considering only the tree specified by Pos.
find_exported_vars_for_sym_label/3 + Gets the exported variables for the top nodes of the clusters linked to + the Name, with type SymType.
find_free_vars_for_sym_label/3 + Gets the free variables for the top nodes of the clusters linked to the Name, + with type SymType.
fold_clusters/4 + Folds a function through the frontiers of the clusters in roughly + breadth first order.
get_children_from_node_list/5 + Gets all the children for a list of nodes and maps them to + the placeholders on the nodes, (their left alternative if common).
get_frontier_children_from_node_list/5 + Gets all the children for a list of nodes and maps them to + the placeholders on the nodes, (their left alternative if common).
get_leaf_as_is_or_default/3 + Obtains information about whether the cluster is a leaf or not.
get_type_list/2 + Returns a list with the correspondence of types, clusters, and trees.
is_in_scope/4 + Returns true if the function specified (Name and Arity) is in + both of sets of inscope functions (Inscope1 and Inscope2), or + false if it is in none.
isolate_type_class/1 + Returns the symmetric cluster type.
merge_environments/2 + Merges the list of free vars of two nodes.
+ +

Function Details

+ +

find_actual_exported_vars_for_asym_label/3

+
+

find_actual_exported_vars_for_asym_label(AsymLabel::{ClustType, string()}, Pos::1 | 2, Acc::cluster_folding:acc()) -> [string()] +

+

+ Gets the exported variables for the top node of the cluster linked to AsymLabel, + considering only the tree specified by Pos. + It first tries to get them from Acc, otherwise it infers it from the node itself.

+ +

find_actual_free_vars_for_asym_label/3

+
+

find_actual_free_vars_for_asym_label(AsymLabel::{ClustType, string()}, Pos::1 | 2, Acc::cluster_folding:acc()) -> [string()] +

+

+ Gets the free variables for the top node of the cluster linked to AsymLabel, + considering only the tree specified by Pos. + It first tries to get them from Acc, otherwise it infers it from the node itself.

+ +

find_exported_vars_for_sym_label/3

+
+

find_exported_vars_for_sym_label(SymType::comm | ex, Name::string(), Name::cluster_folding:acc()) -> [string()]

+

+ Gets the exported variables for the top nodes of the clusters linked to + the Name, with type SymType. It first tires to get them from Acc, + otherwise it infers it from the nodes themselves.

+ +

find_free_vars_for_sym_label/3

+
+

find_free_vars_for_sym_label(SymType::comm | ex, Name::string(), Name::cluster_folding:acc()) -> [string()]

+

+ Gets the free variables for the top nodes of the clusters linked to the Name, + with type SymType. It first tires to get them from Acc, otherwise it infers + it from the nodes themselves.

+ +

fold_clusters/4

+
+

fold_clusters(Fun, AccIn::Acc, ClustInfo, TreeInfo) -> AccOut::Acc +

+

+ Folds a function through the frontiers of the clusters in roughly + breadth first order. + The arguments of the function are:

+ +

get_children_from_node_list/5

+
+

get_children_from_node_list(ClustType, Cluster, Tree, TreeInfo, Nodes::[Node]) -> [{PH, Children}] +

+

+ Gets all the children for a list of nodes and maps them to + the placeholders on the nodes, (their left alternative if common).

+ +

get_frontier_children_from_node_list/5

+
+

get_frontier_children_from_node_list(ClustType, Cluster, Tree, TreeInfo, Nodes::[Node]) -> [{PH, Children}] +

+

+ Gets all the children for a list of nodes and maps them to + the placeholders on the nodes, (their left alternative if common). + It only gets the children that are in a different cluster, not the ones + that are in the same.

+ +

get_leaf_as_is_or_default/3

+
+

get_leaf_as_is_or_default(AsymLabel::{ClustType, string()}, Pos::1 | 2, Acc::cluster_folding:acc()) -> boolean() +

+

+ Obtains information about whether the cluster is a leaf or not. If the + information is no there it defaults to false.

+ +

get_type_list/2

+
+

get_type_list(ClustInfo::cluster_dicts(), TreeInfo::tree_info()) -> [{ClustType, ClusterDict, Tree | na}] +

+

+ Returns a list with the correspondence of types, clusters, and trees. + This can be used to find in which cluster and in which tree a node is.

+ +

is_in_scope/4

+
+

is_in_scope(Name, Arity, Inscope1::sets:set({Name, Arity}), Inscope2::sets:set({Name, Arity})) -> boolean()

+

+ Returns true if the function specified (Name and Arity) is in + both of sets of inscope functions (Inscope1 and Inscope2), or + false if it is in none. This implementation does not contemplate + that it may be in scope for one and not inscope for another, since + that would cause wrong behaviour in the common module.

+ +

isolate_type_class/1

+
+

isolate_type_class(ClustType) -> SymmetricType +

+

+ Returns the symmetric cluster type. That is, removes the information + about which exclusive cluster it is.

+ +

merge_environments/2

+
+

merge_environments(Env1::[string()], Env2::[string()]) -> [string()]

+

+ Merges the list of free vars of two nodes. It removes the repeated + ones.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/cluster_linking.html b/docs/doc/behaviour_extraction/cluster_linking.html new file mode 100644 index 00000000..be33341b --- /dev/null +++ b/docs/doc/behaviour_extraction/cluster_linking.html @@ -0,0 +1,67 @@ + + + + +Module cluster_linking + + + + +
+ +

Module cluster_linking

+ + Gathers information about how the clusters must be linked, in + which order they must be in their respective files, and which + extra functions must be created. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Gathers information about how the clusters must be linked, in + which order they must be in their respective files, and which + extra functions must be created. +

Function Index

+ + + +
get_actual_name/2 + Get the name that the function with name Name is supposed + to have.
get_original_name/2 + Gets the original name that the function with name Name had.
link_clusters/6 + It links the clusters so as to keep the relationships in the original + trees, while keeping the calls to exclusive clusters (from common cluster) + symmetrical, and keeping the number of artifacts used to a minimum.
+ +

Function Details

+ +

get_actual_name/2

+
+

get_actual_name(Name::string(), Acc::cluster_folding:acc()) -> string()

+

+ Get the name that the function with name Name is supposed + to have.

+ +

get_original_name/2

+
+

get_original_name(Name::string(), Acc::cluster_folding:acc()) -> string()

+

+ Gets the original name that the function with name Name had.

+ +

link_clusters/6

+
+

link_clusters(ClusterDict, ClusterDict, ClusterDict, Tree, Tree, Mapping) -> cluster_folding:acc() +

+

+ It links the clusters so as to keep the relationships in the original + trees, while keeping the calls to exclusive clusters (from common cluster) + symmetrical, and keeping the number of artifacts used to a minimum. + It accumulates all information in an #acc{} record that should be enough + to generate the three trees directly.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/cluster_mapping.html b/docs/doc/behaviour_extraction/cluster_mapping.html new file mode 100644 index 00000000..a0931d7f --- /dev/null +++ b/docs/doc/behaviour_extraction/cluster_mapping.html @@ -0,0 +1,68 @@ + + + + +Module cluster_mapping + + + + +
+ +

Module cluster_mapping

+ + Implements the functionality that composes the clusters into + three trees. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Implements the functionality that composes the clusters into + three trees. One with the common clusters, two with each set of + exclusive clusters. It also creates the AST joints, (calls to + functions), which link the clusters together in the resulting + modules. +

Data Types

+ +

col_data()

+

col_data() = #col_data{beh_funcs = sets:set({atom(), integer()}), module_info1 = sets:set({atom(), integer()}), module_info2 = sets:set({atom(), integer()}), inscope_funs1 = [{atom(), atom(), integer()}], inscope_funs2 = [{atom(), atom(), integer()}], var_for_module = string()}

+

Record for use as accumulator when mapping clusters. + It collects global information about the generated + modules. + Contains the following fields:

+ +

Function Index

+ +
clusters_to_ast/2 + It generates three ASTs, one for each cluster dictionary.
+ +

Function Details

+ +

clusters_to_ast/2

+
+

clusters_to_ast(Acc::cluster_folding:acc(), OutModule::atom()) -> [wrangler_syntax:syntaxTree()]

+

+ It generates three ASTs, one for each cluster dictionary.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:18.

+ + diff --git a/docs/doc/behaviour_extraction/da_map.html b/docs/doc/behaviour_extraction/da_map.html new file mode 100644 index 00000000..dd0df70d --- /dev/null +++ b/docs/doc/behaviour_extraction/da_map.html @@ -0,0 +1,161 @@ + + + + +Module da_map + + + + +
+ +

Module da_map

+ + It implements a double associative map. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ It implements a double associative map. It is a key-value + storage that can be queried through both the key and the + value. +

Data Types

+ +

da_map()

+

abstract datatype: da_map(Key, Value)

+ + +

Function Index

+ + + + + + + + + + + + +
delete_by_key/2 + Remove the entry with Key as key from the DaMap if it exists.
delete_by_value/2 + Remove the entry with Value as value from the DaMap if it exists.
find_key/2 + Returns {ok, Key} if there is an entry with Value as value + in the da_map, returns error otherwise.
find_value/2 + Returns {ok, Value} if there is an entry with Key as key in + the da_map, returns error otherwise.
fold/3 + Folds the function Fun through all the entries of the DaMap.
has_key/2 + Returns true if there is an entry with Key as key in the da_map, + returns false otherwise.
has_pair/3 + Returns true if there is an entry with Key as key and Value as + value in the DaMap, returns false otherwise.
has_value/2 + Returns true if there is an entry with Value as value in the + DaMap, returns false otherwise.
new/0 + It creates an empty da_map.
put/3 + Stores an entry with Key as key and Value as value in the DaMap.
size/1 + Returns the number of entries of the DaMap.
union/2 + Joins DaMap1 and DaMap2 by inserting all the entries of DaMap2 in + DaMap1.
+ +

Function Details

+ +

delete_by_key/2

+
+

delete_by_key(Key, DaMap::da_map(Key, Value)) -> da_map(Key, Value) +

+

+ Remove the entry with Key as key from the DaMap if it exists.

+ +

delete_by_value/2

+
+

delete_by_value(Value, DaMap::da_map(Key, Value)) -> da_map(Key, Value) +

+

+ Remove the entry with Value as value from the DaMap if it exists.

+ +

find_key/2

+
+

find_key(Value, DaMap::da_map(Key, Value)) -> {ok, Key} | error +

+

+ Returns {ok, Key} if there is an entry with Value as value + in the da_map, returns error otherwise.

+ +

find_value/2

+
+

find_value(Key, DaMap::da_map(Key, Value)) -> {ok, Value} | error +

+

+ Returns {ok, Value} if there is an entry with Key as key in + the da_map, returns error otherwise.

+ +

fold/3

+
+

fold(Fun, AccIn::Acc, DaMap::da_map(Key, Value)) -> AccOut::Acc +

+

+ Folds the function Fun through all the entries of the DaMap.

+

See also: dict:fold/3.

+ +

has_key/2

+
+

has_key(Key, DaMap::da_map(Key, any())) -> boolean() +

+

+ Returns true if there is an entry with Key as key in the da_map, + returns false otherwise.

+ +

has_pair/3

+
+

has_pair(Key, Value, DaMap::da_map(Key, Value)) -> boolean() +

+

+ Returns true if there is an entry with Key as key and Value as + value in the DaMap, returns false otherwise.

+ +

has_value/2

+
+

has_value(Value, DaMap::da_map(any(), Value)) -> boolean() +

+

+ Returns true if there is an entry with Value as value in the + DaMap, returns false otherwise.

+ +

new/0

+
+

new() -> da_map(any(), any())

+

+ It creates an empty da_map.

+ +

put/3

+
+

put(Key, Value, DaMap::da_map(Key, Value)) -> da_map(Key, Value) +

+

+ Stores an entry with Key as key and Value as value in the DaMap. + It removes all existing entries with Key as key or Value as value.

+ +

size/1

+
+

size(DaMap::da_map(any(), any())) -> non_neg_integer()

+

+ Returns the number of entries of the DaMap.

+ +

union/2

+
+

union(DaMap1::da_map(Key, Value), DaMap2::da_map(Key, Value)) -> da_map(Key, Value) +

+

throws da_maps_not_disjoint

+

+ Joins DaMap1 and DaMap2 by inserting all the entries of DaMap2 in + DaMap1. It assumes DaMap1 and DaMap2 are disjoint in terms of both + their keys and their values. It throws da_maps_not_disjoint if + DaMap1 and DaMap2 are not disjoint in terms of keys or values.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/erlang.png b/docs/doc/behaviour_extraction/erlang.png new file mode 100644 index 00000000..987a618e Binary files /dev/null and b/docs/doc/behaviour_extraction/erlang.png differ diff --git a/docs/doc/behaviour_extraction/fix_frontiers.html b/docs/doc/behaviour_extraction/fix_frontiers.html new file mode 100644 index 00000000..04ca9f65 --- /dev/null +++ b/docs/doc/behaviour_extraction/fix_frontiers.html @@ -0,0 +1,67 @@ + + + + +Module fix_frontiers + + + + +
+ +

Module fix_frontiers

+ + Moves the frontiers of the clusters so that functions can + be extracted from them. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Moves the frontiers of the clusters so that functions can + be extracted from them. This is done by reducing the size + of the common clusters, and expanding the size of the + exclusive clusters. +

Function Index

+ + + +
delete_trivial_clusters/1 + Removes from the CommClusterDict and detaches from the Mapping every + cluster with a single node in it.
fix_frontiers/5 + Moves the frontiers of the clusters to places where function + calls can be used to divide the trees.
node_exports_vars/2 + Returns true if either Node (assumed to belong to Tree), exports + variables.
+ +

Function Details

+ +

delete_trivial_clusters/1

+
+

delete_trivial_clusters(X1::{CommClusterDict::cluster_dict:cluster_dict(tree:tree_node()), Mapping::da_map:da_map(tree:tree_node(), tree:tree_node())}) -> {cluster_dict:cluster_dict(tree:tree_node()), da_map:da_map(tree:tree_node(), tree:tree_node())}

+

+ Removes from the CommClusterDict and detaches from the Mapping every + cluster with a single node in it.

+ +

fix_frontiers/5

+
+

fix_frontiers(Pass::1 | 2, Tree1::tree:tree(), Tree2::tree:tree(), Mapping::da_map:da_map(tree:tree_node(), tree:tree_node()), CommCluster::cluster_dict:cluster_dict(tree:tree_node())) -> {cluster_dict:cluster_dict(tree:tree_node()), da_map:da_map(tree:tree_node(), tree:tree_node())}

+

+ Moves the frontiers of the clusters to places where function + calls can be used to divide the trees. + This function updates both the Mapping and the CommCluster + dictionary. The right exclusive clusters are generated from the + fixed Mapping at tree_clustering:cluster/3

+ +

node_exports_vars/2

+
+

node_exports_vars(Node::tree:tree_node(), Tree::tree:tree()) -> boolean()

+

+ Returns true if either Node (assumed to belong to Tree), exports + variables.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/fun_blocks.html b/docs/doc/behaviour_extraction/fun_blocks.html new file mode 100644 index 00000000..89e149b5 --- /dev/null +++ b/docs/doc/behaviour_extraction/fun_blocks.html @@ -0,0 +1,71 @@ + + + + +Module fun_blocks + + + + +
+ +

Module fun_blocks

+ + Tools to join several instructions in the same block. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Tools to join several instructions in the same block. + This is done to avoid the creation of several contiguous functions + which could be expressed as a single one. +

Function Index

+ + + + +
add_blocks_to_trees/6 + Searches for functions with several consecutive mapped/unmapped + children in the frontier and groups them into block expressions.
create_artificial_block_value/2 + Creates a block expression with ChildrenPHs as subtrees and + sets the position and the range to something useful.
get_body/1 + Returns the body of a clause or block expression (ClauseOrBlock).
replace_children_in_body/3 + Replaces the old subtrees (OldChildren) in the body of NodeValue + with the new subtrees (NewChildren), leaving the rest untouched.
+ +

Function Details

+ +

add_blocks_to_trees/6

+
+

add_blocks_to_trees(LeftTree::tree:tree(), RightTree::tree:tree(), Mapping::da_map:da_map(tree:tree_node(), tree:tree_node()), CommCluster::cluster_dict:cluster_dict(tree:tree_node()), ExLeftClus::cluster_dict:cluster_dict(tree:tree_node()), ExRightClus::cluster_dict:cluster_dict(tree:tree_node())) -> {tree:tree(), tree:tree()}

+

+ Searches for functions with several consecutive mapped/unmapped + children in the frontier and groups them into block expressions.

+ +

create_artificial_block_value/2

+
+

create_artificial_block_value(Tree::tree:tree(), ChildrenPHs::[tree:tree_ph()]) -> wrangler_syntax:syntaxTree()

+

+ Creates a block expression with ChildrenPHs as subtrees and + sets the position and the range to something useful.

+ +

get_body/1

+
+

get_body(ClauseOrBlock::wrangler_syntax:syntaxTree()) -> [wrangler_syntax:syntaxTree()]

+

+ Returns the body of a clause or block expression (ClauseOrBlock).

+ +

replace_children_in_body/3

+
+

replace_children_in_body(OldChildren::[El], NewChildren::[El], NodeValue::wrangler_syntax:syntaxTree()) -> wrangler_syntax:syntaxTree()

+

+ Replaces the old subtrees (OldChildren) in the body of NodeValue + with the new subtrees (NewChildren), leaving the rest untouched. + It assumes that the node (NodeValue) is a clause or a block expression.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:18.

+ + diff --git a/docs/doc/behaviour_extraction/fun_blocks_fix.html b/docs/doc/behaviour_extraction/fun_blocks_fix.html new file mode 100644 index 00000000..48b1134c --- /dev/null +++ b/docs/doc/behaviour_extraction/fun_blocks_fix.html @@ -0,0 +1,43 @@ + + + + +Module fun_blocks_fix + + + + +
+ +

Module fun_blocks_fix

+ + Removes artificial blocks that are expected to both return and + export variables at the same time. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Removes artificial blocks that are expected to both return and + export variables at the same time. +

Function Index

+ +
export_variables/3 + Removes blocks that are expected to return and export variables + at the same time.
+ +

Function Details

+ +

export_variables/3

+
+

export_variables(LeftTree::tree:tree(), RightTree::tree:tree(), Mapping::da_map:da_map(tree:tree_node(), tree:tree_node())) -> {Tree::tree:tree(), Tree::tree:tree()}

+

+ Removes blocks that are expected to return and export variables + at the same time. If possible it will just remove the last + item from the blocks.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/index.html b/docs/doc/behaviour_extraction/index.html new file mode 100644 index 00000000..eabafe6c --- /dev/null +++ b/docs/doc/behaviour_extraction/index.html @@ -0,0 +1,18 @@ + + + +The behaviour_extraction application + + + + + + + +<h2>This page uses frames</h2> +<p>Your browser does not accept frames. +<br>You should go to the <a href="overview-summary.html">non-frame version</a> instead. +</p> + + + diff --git a/docs/doc/behaviour_extraction/infer_behaviour.html b/docs/doc/behaviour_extraction/infer_behaviour.html new file mode 100644 index 00000000..c1786288 --- /dev/null +++ b/docs/doc/behaviour_extraction/infer_behaviour.html @@ -0,0 +1,44 @@ + + + + +Module infer_behaviour + + + + +
+ +

Module infer_behaviour

+ + Top level for the behaviour generation refactoring. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Top level for the behaviour generation refactoring. +

Function Index

+ +
infer_behaviour/6 + Takes two input files (LeftFile and RightFile) and an output + file (OutputFile), and tries to create a behaviour definition in + OutputFile with the common parts of the inputs files while + transforming the input files into behaviour instances of OutputFile.
+ +

Function Details

+ +

infer_behaviour/6

+
+

infer_behaviour(LeftFile::string(), RightFile::string(), OutputFile::string(), SearchPaths::[string()], Editor::atom(), TabWidth::non_neg_integer()) -> {ok, [any()]}

+

+ Takes two input files (LeftFile and RightFile) and an output + file (OutputFile), and tries to create a behaviour definition in + OutputFile with the common parts of the inputs files while + transforming the input files into behaviour instances of OutputFile.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/local_fix.html b/docs/doc/behaviour_extraction/local_fix.html new file mode 100644 index 00000000..ac5454e4 --- /dev/null +++ b/docs/doc/behaviour_extraction/local_fix.html @@ -0,0 +1,54 @@ + + + + +Module local_fix + + + + +
+ +

Module local_fix

+ + Implements the functionality that redirects local calls and ?MODULE + macros to their original modules. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Implements the functionality that redirects local calls and ?MODULE + macros to their original modules. It also adds the Module variable + where appropriate to the existing function headers. Only comm cluster. +

Function Index

+ + +
add_fun_to_col/3 + Adds the Name and Arity to the field beh_funcs of ColData.
fix_localities/4 + Fixes the SyntaxTree to behave as it did in the original module (by + redirecting references and the ?MODULE macro).
+ +

Function Details

+ +

add_fun_to_col/3

+
+

add_fun_to_col(ColData::cluster_mapping:col_data(), Name::string(), Arity::integer()) -> cluster_mapping:col_data()

+

+ Adds the Name and Arity to the field beh_funcs of ColData.

+ +

fix_localities/4

+
+

fix_localities(IsLeafOrExc::boolean(), SyntaxTree::wrangler_syntax:syntaxTree(), HasFuncDec::boolean(), ColData::cluster_mapping:col_data()) -> {wrangler_syntax:syntaxTree(), cluster_mapping:col_data()}

+

+ Fixes the SyntaxTree to behave as it did in the original module (by + redirecting references and the ?MODULE macro). + IsLeafOrExc must be true if the tree is known to have no references + or if it is in an exclusive cluster. HasFuncDec must be true + the root of the SyntaxTree is a legacy function declaration.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/modules-frame.html b/docs/doc/behaviour_extraction/modules-frame.html new file mode 100644 index 00000000..01d82cdb --- /dev/null +++ b/docs/doc/behaviour_extraction/modules-frame.html @@ -0,0 +1,26 @@ + + + +The behaviour_extraction application + + + +

Modules

+ + + + + + + + + + + + + + + +
ast_tree
cluster
cluster_dict
cluster_folding
cluster_linking
cluster_mapping
da_map
fix_frontiers
fun_blocks
fun_blocks_fix
infer_behaviour
local_fix
tree
tree_clustering
tree_mapping
+ + \ No newline at end of file diff --git a/docs/doc/behaviour_extraction/overview-summary.html b/docs/doc/behaviour_extraction/overview-summary.html new file mode 100644 index 00000000..2c21726f --- /dev/null +++ b/docs/doc/behaviour_extraction/overview-summary.html @@ -0,0 +1,36 @@ + + + + +Automatic behaviour inference + + + + +

Automatic behaviour inference

+

Copyright © (C) 2015 Pablo Lamela, Simon Thompson

+

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ + +

This package provides a mechanism that automatically creates an Erlang behaviour by merging two modules selected by the user, which are assumed to be structurally similar, and possibly the result of copying and modifying one of them to produce the other.

+ +

The algorithm consists of four main stages:

+ + + +

The process starts with two modules which are assumed to be similar. First we find commonalities between their ASTs, group the contiguous commonalities, move the commonalities to a separate module, and link the pieces together with function calls in order to preserve the original behaviour. This way we are left with three modules: the remains of the original ones and a new module with the common parts. The module with the common code will be configured as a behaviour definition, and modules with the remainings of the original ones will be configured as behaviour instances of the new module.

+ +

The top level module for the algorithm is infer_behaviour.

+ +Module graph + +
+ +

Generated by EDoc, Nov 12 2015, 18:43:11.

+ + diff --git a/docs/doc/behaviour_extraction/stylesheet.css b/docs/doc/behaviour_extraction/stylesheet.css new file mode 100644 index 00000000..ab170c09 --- /dev/null +++ b/docs/doc/behaviour_extraction/stylesheet.css @@ -0,0 +1,55 @@ +/* standard EDoc style sheet */ +body { + font-family: Verdana, Arial, Helvetica, sans-serif; + margin-left: .25in; + margin-right: .2in; + margin-top: 0.2in; + margin-bottom: 0.2in; + color: #000000; + background-color: #ffffff; +} +h1,h2 { + margin-left: -0.2in; +} +div.navbar { + background-color: #add8e6; + padding: 0.2em; +} +h2.indextitle { + padding: 0.4em; + background-color: #add8e6; +} +h3.function,h3.typedecl { + background-color: #add8e6; + padding-left: 1em; +} +div.spec { + margin-left: 2em; + background-color: #eeeeee; +} +a.module { + text-decoration:none +} +a.module:hover { + background-color: #eeeeee; +} +ul.definitions { + list-style-type: none; +} +ul.index { + list-style-type: none; + background-color: #eeeeee; +} + +/* + * Minor style tweaks + */ +ul { + list-style-type: square; +} +table { + border-collapse: collapse; +} +td { + padding: 3 +} diff --git a/docs/doc/behaviour_extraction/tree.html b/docs/doc/behaviour_extraction/tree.html new file mode 100644 index 00000000..7042cc3f --- /dev/null +++ b/docs/doc/behaviour_extraction/tree.html @@ -0,0 +1,301 @@ + + + + +Module tree + + + + +
+ +

Module tree

+ + Implements an indexed tree with isolated nodes. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Implements an indexed tree with isolated nodes. +

Data Types

+ +

tree()

+

abstract datatype: tree()

+ + +

tree_node()

+

abstract datatype: tree_node()

+ + +

tree_ph()

+

abstract datatype: tree_ph()

+ + +

Function Index

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
breadth_fold/3 + Folds a function through a tree in breadth first order.
collapse_node/2 + Removes the node from the tree, and attaches its children to + its parent in the place it was.
copy_properties/2 + Copies the properties stored in the nodes of OriTree into + the nodes of DestTree.
create_node_pair/2 + Joins two nodes into a single node (node pair).
dict_get/3 + Like dict:fetch/2 but allows to specify a default value.
get_child_ph/1 + Generates a placeholder for a child of the node.
get_children/2 + Returns the children of Node in the Tree.
get_data/1 + Returns the extra information stored on the tree.
get_node/2 + Finds a node by using its placeholder.
get_pair_tuple/1 + Splits a node pair into the original two nodes.
get_parent/2 + Returns the parent of Node in the Tree.
get_ph/1 + Returns the placeholder for a node or node pair Node.
get_pos_in_parent/2 + Finds the position of Node in the list of children + of Parent.
get_property/2 + Extracts the value of a property from a tree_node.
get_root_node/1 + Returns the root node of the Tree.
get_value/1 + Extracts the value from a tree_node.
group_children/5 + Moves the children with PH ChildrenPHs to a new node, and + puts the new node in the place of the children, it returns + both the new node and the updated tree.
index_by/2 + Returns a map with the nodes of the Tree as values and the + result of applying Fun to them as keys.
is_node_pair/1 + Returns whether a node is a node pair.
new/0 + Creates a empty tree.
new_node_ph/1 + Creates a node from a placeholder.
replace_with_elements/3 + Replaces the first occurrence of Pattern in List with the elements + in the list Replacement.
set_data/2 + Sets the extra information stored on the tree.
set_property/3 + Sets the value property for a tree_node.
set_value/2 + Sets the value for a tree_node.
store_node/2 + Adds a new node to the tree, or updates an existing one.
upgrade_node/2 + Moves a node upwards a level.
+ +

Function Details

+ +

breadth_fold/3

+
+

breadth_fold(Fun::FFun, AccIn::Acc, Tree::tree()) -> AccOut::Acc +

+

+ Folds a function through a tree in breadth first order.

+ +

collapse_node/2

+
+

collapse_node(Tree_node, Tree) -> any()

+

+ Removes the node from the tree, and attaches its children to + its parent in the place it was. It expects the value of the + parent to be updated appropriately.

+ +

copy_properties/2

+
+

copy_properties(OriTree::tree:tree(), DestTree::tree:tree()) -> tree:tree()

+

+ Copies the properties stored in the nodes of OriTree into + the nodes of DestTree. Both trees must have the same exact + topology.

+ +

create_node_pair/2

+
+

create_node_pair(Node1::tree:tree_node(), Node2::tree:tree_node()) -> tree:tree_node()

+

+ Joins two nodes into a single node (node pair)

+ +

dict_get/3

+
+

dict_get(Key::KeyType, Dict::dict:dict(KeyType, ValueType), DefaultValue::ValueType) -> ValueType

+

+ Like dict:fetch/2 but allows to specify a default value.

+ +

get_child_ph/1

+
+

get_child_ph(Tree_node::tree_node()) -> {tree_node(), tree_ph()}

+

+ Generates a placeholder for a child of the node. A child generated + with the placeholder will be linked automatically to the node. + For the link to be created, the version of the node updated by + this function must be stored in the tree afterwards, + store_node/2, as well as the child generated with the + placeholder.

+ +

get_children/2

+
+

get_children(Node::tree:tree_node(), Tree::tree()) -> [tree:tree_node()]

+

+ Returns the children of Node in the Tree.

+ +

get_data/1

+
+

get_data(Tree::tree:tree()) -> Data::any()

+

+ Returns the extra information stored on the tree. + This can be any term and is stored with set_data/2.

+ +

get_node/2

+
+

get_node(PH::tree_ph(), Tree::tree()) -> error | {ok, tree_node()}

+

+ Finds a node by using its placeholder. It returns error if it + cannot be found.

+ +

get_pair_tuple/1

+
+

get_pair_tuple(NodePair::tree:tree_node()) -> {tree:tree_node(), tree:tree_node()}

+

+ Splits a node pair into the original two nodes

+ +

get_parent/2

+
+

get_parent(Node::tree:tree_node(), Tree::tree()) -> error | {ok, tree:tree_node()}

+

+ Returns the parent of Node in the Tree.

+ +

get_ph/1

+
+

get_ph(Node::tree:tree_node()) -> {node, tree:tree_ph()} | {node_pair, tree:tree_ph(), tree:tree_ph()}

+

+ Returns the placeholder for a node or node pair Node. That is, + an unique identifier for the Node, that is used as placeholder + in the original position of the node in its parent. + If Node is a node pair, two placeholders are returned.

+ +

get_pos_in_parent/2

+
+

get_pos_in_parent(Node::tree:tree_node(), Parent::tree:tree_node()) -> error | pos_integer()

+

+ Finds the position of Node in the list of children + of Parent.

+ +

get_property/2

+
+

get_property(Key::term(), Node::tree_node()) -> {ok, Value::term()} | error

+

+ Extracts the value of a property from a tree_node. Returns error + if it is not set.

+ +

get_root_node/1

+
+

get_root_node(Tree::tree()) -> tree:tree_node()

+

+ Returns the root node of the Tree.

+ +

get_value/1

+
+

get_value(Tree_node::tree_node()) -> term()

+

+ Extracts the value from a tree_node.

+ +

group_children/5

+
+

group_children(Tree_node::tree_node(), ChildrenPHs::[tree_ph()], NewParentValueGen::fun((PH::tree_node()) -> Value), Value, Tree::tree()) -> {tree_node(), tree:tree()} +

+

+ Moves the children with PH ChildrenPHs to a new node, and + puts the new node in the place of the children, it returns + both the new node and the updated tree. + A value, both for the parent and the new node which reflect + the changes, is required. + All nodes are assumed to NOT be node pairs, (before and after).

+ +

index_by/2

+
+

index_by(Fun::fun((Node) -> Idx), Tree::tree()) -> dict:dict(Idx, Node) +

+

+ Returns a map with the nodes of the Tree as values and the + result of applying Fun to them as keys.

+ +

is_node_pair/1

+
+

is_node_pair(Node::tree:tree_node()) -> boolean()

+

+ Returns whether a node is a node pair

+ +

new/0

+
+

new() -> tree()

+

+ Creates a empty tree

+ +

new_node_ph/1

+
+

new_node_ph(PH::tree_ph()) -> tree_node()

+

+ Creates a node from a placeholder. See get_child_ph/1.

+ +

replace_with_elements/3

+
+

replace_with_elements(Pattern::[El], List::[El], Replacement::[El]) -> [El] +

+

+ Replaces the first occurrence of Pattern in List with the elements + in the list Replacement. It assumes there no partial matches.

+ +

set_data/2

+
+

set_data(Data::any(), Tree::tree:tree()) -> NewTree::tree:tree()

+

+ Sets the extra information stored on the tree. + This can be any term and is retrieved from the tree with + get_data/1.

+ +

set_property/3

+
+

set_property(Key::term(), Value::term(), Node::tree_node()) -> tree_node()

+

+ Sets the value property for a tree_node. It does not update the tree, + obviously. For updating the tree the node must be stored + afterwards, store_node/2.

+ +

set_value/2

+
+

set_value(Value::term(), Node::tree_node()) -> tree_node()

+

+ Sets the value for a tree_node. It does not update the tree, + obviously. For updating the tree the node must be stored + afterwards, store_node/2.

+ +

store_node/2

+
+

store_node(Node::tree:tree_node(), Tree::tree()) -> tree()

+

+ Adds a new node to the tree, or updates an existing one.

+ +

upgrade_node/2

+
+

upgrade_node(Tree_node, Tree) -> any()

+

+ Moves a node upwards a level. It expects the value of the + two ancestors to be updated appropriately.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:18.

+ + diff --git a/docs/doc/behaviour_extraction/tree_clustering.html b/docs/doc/behaviour_extraction/tree_clustering.html new file mode 100644 index 00000000..568f8531 --- /dev/null +++ b/docs/doc/behaviour_extraction/tree_clustering.html @@ -0,0 +1,47 @@ + + + + +Module tree_clustering + + + + +
+ +

Module tree_clustering

+ + Functions to divide mapped trees in clusters. +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Functions to divide mapped trees in clusters +

Function Index

+ +
cluster/4 + Takes two trees and a Mapping between them, divides the + trees in contiguous clusters.
+ +

Function Details

+ +

cluster/4

+
+

cluster(Pass, Mapping, Tree1::tree:tree(), Tree2::tree:tree()) -> {Mapping, cluster_dict:cluster_dict(tree:tree_node()), cluster_dict:cluster_dict(tree:tree_node()), cluster_dict:cluster_dict(tree:tree_node())} +

+

+ Takes two trees and a Mapping between them, divides the + trees in contiguous clusters. The criteria for division + is that the nodes in a cluster must be contiguous and + either common to both trees, or exclusive to one of them. + It applies fix_frontiers:fix_frontiers/4. + The function returns a tuple with three elements: + the list of common clusters, the list of exclusive clusters + for Tree1, the list of exclusive clusters for Tree2.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/behaviour_extraction/tree_mapping.html b/docs/doc/behaviour_extraction/tree_mapping.html new file mode 100644 index 00000000..cf0bb3de --- /dev/null +++ b/docs/doc/behaviour_extraction/tree_mapping.html @@ -0,0 +1,44 @@ + + + + +Module tree_mapping + + + + +
+ +

Module tree_mapping

+ + Implementation of the algorithm described in paper: + "diffX: an algorithm to detect changes in multi-version XML documents" + by: + "Raihan Al-Ekram, Archana Adma and Olga Baysal". +

Copyright © (C) 2015, Pablo Lamela, Simon Thompson

+ +

Authors: Pablo Lamela Seijas (P.Lamela-Seijas@kent.ac.uk), Simon Thompson (S.J.Thompson@kent.ac.uk).

+ +

Description

+ Implementation of the algorithm described in paper: + "diffX: an algorithm to detect changes in multi-version XML documents" + by: + "Raihan Al-Ekram, Archana Adma and Olga Baysal" +

Function Index

+ +
mapping/2 + Takes two trees and returns a mapping between their common nodes.
+ +

Function Details

+ +

mapping/2

+
+

mapping(T1::tree:tree(), T2::tree:tree()) -> da_map:da_map(tree:tree_node(), tree:tree_node())

+

+ Takes two trees and returns a mapping between their common nodes.

+
+ + +

Generated by EDoc, Nov 5 2015, 16:30:19.

+ + diff --git a/docs/doc/erlang.png b/docs/doc/erlang.png new file mode 100644 index 00000000..987a618e Binary files /dev/null and b/docs/doc/erlang.png differ diff --git a/docs/doc/gen_composite_refac.html b/docs/doc/gen_composite_refac.html new file mode 100644 index 00000000..f1b4194c --- /dev/null +++ b/docs/doc/gen_composite_refac.html @@ -0,0 +1,259 @@ + + + + +Module gen_composite_refac + + + + +
+ +

Module gen_composite_refac

+This module defines the gen_composite_refac behaviour. + +

This module defines the gen_composite_refac behaviour.
Required callback functions: composite_refac/1, input_par_prompts/0, select_focus/1.

+

Authors: Huiqing Li (H.Li@kent.ac.uk).

+ +

Description

This module defines the gen_composite_refac behaviour. It provides a high-level +abstraction of the logic work-flow of a composite refactoring process. The behaviour +defines two callback functions that are to be implemented by the user as explained next.

+ + Callback function input_par_prompts/0: +
     input_par_prompts()
+       ===> [string()]
+ input_par_prompts returns the list of prompt strings to be used when + the refactorer asks the user for input at the very beginning of the composite + refactoring. There should be one prompt string for each input. + Callback function composite_refac/1: +
     composite_refac(Args::#args{})
+        ===> composite_refac()|[]

+ composite_refac is the function in which the user could script a + composite refactoring. The definition of record args is the same as the + the record using by the gen_refac behaviour to be consistent, but the + selective field should not be used.

+ + Record args defines the data structure that is passed to composite_refac. +
      -record(args,{current_file_name :: filename(),         %% the file name of the current Erlang buffer.
+                    cursor_pos        :: pos(),              %% the current cursor position.
+                    highlight_range   :: {pos(), pos()},     %% the start and end location of the highlighted code if there is any.
+                    user_inputs       :: [string()],         %% the data inputted by the user.
+                    focus_sel         :: any(),              %% the focus of interest selected by the user.
+                    search_paths      ::[dir()|filename()],  %% the list of directories or files which specify the scope of the project.
+                    tabwidth =8        ::integer()           %% the number of white spaces denoted by a tab key.
+                   }).
+ +

Before explaining how to scripting composite refactorings, we clarify the meaning +of some terms we use.

+ +

Precondition . A precondition is a predicate over a program that returns + either true or false when applied to a program.

+ +

Transformation rule. A transformation rule maps a program from one state into another.

+ +

Refactoring. A refactoring is either a elementary refactoring or a composite refactoring.

+ +

Elementary refactoring. A elementary refactoring is an elementary behaviour-preserving + source-to-source program transformation that consists of a set of preconditions C, + and a set of transformation rules T. When a elementary refactoring is applied to a + program, all the preconditions are checked before the programming is actually transformed. + We say a elementary refactoring fails if the conjunction of the set of + preconditions returns false; otherwise we say the elementary refactoring succeeds .

+ +

Composite Refactoring. A composite refactoring is either an atomic composite +refactoring or a non-atomic composite refactoring.

+ +

Atomic composite refactoring Given a sequence of elementary refactorings, R_1, ..., R_n(n>=1), + the atomic composition of R_1, ..., R_n, creates a new refactoring consisting of + the sequential application of refactorings from R_1 to R_n. If any R_i(1=<i=<n) fails, + then the whole refactoring fails and the original program returns unchanged. + The composite refactoring succeeds if all R_i(1=<i=<n) succeeds, and the result + program is the program returned after applying R_n.

+ +

Non-atomic composite refactoring + Given a sequence of refactorings R_1, ..., Rn(n>=1), the non-atomic composition of R_1, ..., R_n, + creates a new refactoring consisting of the sequential application of refactorings from + R_1 to R_n. If refactoring R_i fails, the execution of R_{i+1} continues. A failed refactoring + does not change the status of the program. The program returned by applying R_n is the final result +of the application of the composite refactoring. As a convention, we say that a non-atomic +composite refactoring always succeeds.

+ +

Refactoring Command Generators

+Each primitive refactoring in Wrangler has been extended with a refactoring command generator. The +interface of a command generator is enriched in such a way that it accepts not only concrete values +as what a primitive refactoring does, but also structures that specify the constraints that a parameter +should meet or structures that specify how the value for a parameter should be generated.

+ +

When applied to an Erlang program, a command generator searches the AST representation of the program +for refactoring candidates according to the constraints on arguments. A command generator can also be +instructed to run lazily or strictly; if applied strictly, it returns the complete list of primitive +refactoring commands that can be generated in one go; otherwise, it returns a single refactoring +command together with another command generator wrapped in a function closure, or an empty list +if no more commands can be generated. Lazy refactoring command generation is especially useful +when the primitive refactoring command refers some program entities by locations, or the +effect of a previous refactoring could affect the refactorings after.

+ +

Each primitive refactoring command generated is represented as a tuple in the format of: + {refactoring, RefacName, Args}, where RefacName is the name of the refactoring command, + and Args is the list representation of the arguments for that refactoring command. + A refactoring command generator is also syntactically represented as a three-element tuple, + but with a different tag, in the format of {refac_, RefacName, Args}, where RefacName is + the name of the refactoring, and Args are the arguments that supplied to the command generator.

+ + Take the rename function refactoring as an example, the type specification of the refactoring + command is: +
      -spec rename_fun(File::filename(), FunNameArity::{atom(), integer()},
+                   NewName::atom()) -> ok | {error, Reason::string()}.
+ which should be clear enough to explain itself. + The type specification of the command generator is: +
     -spec rename_fun(File::filename() | fun((filename()) -> boolean()),
+                   FunNameArity::{atom(), integer()}
+                                | fun(({atom(),integer()}) -> boolean()),
+                   NewName::atom()
+                     |{generator, fun(({filename(), {atom(), integer()}})
+                                      -> atom())}
+  	                   |{user_input,fun(({filename(), {atom(), integer()}})
+                                     -> string())},
+                   Lazy :: boolean())
+             -> [{refactoring, rename_fun, Args::[term()]}] |
+                {{refactoring, rename_fun, Args::[term()]}, function()}.

+As it shows, a command generator accepts not only actual values, but also function closures +that allow values to be generated by analyzing the code to be refactored . The first parameter +of the generator accepts either a file name, or a condition that a file should satisfy to be +refactored. In the latter case, Wrangler will search the whole program for files that meet +the condition specified, and only those files are further analyzed in order to generate values +for the remaining parameters. The second parameter accepts either a function name tupled with +its arity, or a condition that a function should meet in order to be refactored. In the latter +case, every function in an Erlang file will be checked, and those functions that do not meet +the condition are filtered out, and a primitive refactoring command is generated for each function +that meets the condition. The third argument specifies how the new function name should be generated. +It could be a fixed function name, a generator function that generates the new function based on the +previous parameter values, or a name that will be supplied by the user before the execution of the +refactoring, in which case the function closure is used to generate the prompt string that will be +shown to the user when prompting for input. Finally, the last parameter allows the user to choose +whether to generate the commands lazily or not.

+ + The following example illustrates the generation of refactoring commands that rename all functions + in a program whose name is in camelCase format to camel _case format. +
       {refac_, rename_fun, [fun(_File)-> true end,
+                             fun({FunName, _Arity}) -> is_camelCase(FunName) end,
+                             {generator, fun({_File,{FunName,_Arity}}) ->
+                                            camelCase_to_camel_case(FunName)
+                                         end}, false]}

+ As the condition for the first parameter always returns true, every file in the program should be checked. + The second argument checks if the function name is in camelCase format using the utility function + is_camelCase, and a refactoring command is generated for each function whose name is in camelCase format. + The new function name is generated by applying the utility function camelCase_to_camel_case to the old +function name. In this example, we choose to generate the refactoring commands in a strict way.

+ +

For some command generators, it is also possible to specify the order in which the functions in an +Erlang file are visited. By default, functions are visited by their textual order in the file, but it +is also possible for them to be visited according to the function callgraph in either top-down or +bottom-up order.

+ +

For the type specification of refactoring command generators, please see + wrangler command generators.

+ +

To allow fine control over the generation of refactoring commands and the way a refactoring command + to be run, we have defined a small language for scripting composite refactorings. The DSL, as shown + below, is defined in Erlang syntax. In the definition, ER denotes a primitive refactoring, and CR + denotes a composite refactoring. we explain the definition of CR in more details now.

+ +
          RefacName ::= rename_fun | rename_mod | rename_var | new_fun |gen_fun | ... 	
+          ER ::= {refactoring, RefacName, Args}
+          CR ::= ER
+                |{interactive, Qualifier, [ERs]}
+                |{repeat_interactive, Qualifier, [ERs]}
+                |{if_then, fun()-> Cond end, CR} 	
+                |{while, fun()-> Cond end, Qualifier, CR}
+                |{Qualifier, [CRs]}
+          ERs::= ER | ERs, ER
+          CRs ::= CR |CRs, CR 	
+          Qualifier ::= atomic | non_atomic
+          Args ::= ...A list of Erlang terms ...
+          Cond ::=  ...An Erlang expression that evaluates to a  `boolean' value ...
+ +

The definition of CR is explained in more details below. + A primitive refactorings is an atomic composite refactoring by definition. + {interactive, Qualifier, [ERs]} represents a list of primitive refactorings that to be + executed in an interactive way, that is, before the execution of every primitive refactoring, + Wrangler asks the user for confirmation that he/she really wants that refactoring to be applied. + {repeat_interactive, Qualifier, [ERs]} also represents a list of primitive refactorings to be + executed in an interactive way, but different from the previous one, it allows user to repeatedly + apply one refactoring, with different parameters supplied, multiple times. + {if_then, Cond, CR} represents the conditional application of CR, i.e. CR is applied only + if Cond, which is an Erlang expression, evaluates to true. + {while, Cond, Qualifier, CR} allows CR, which should be generated dynamically, to be continually + applied until $Cond$ evaluates to false. Qualifier specifies the way in which + the refactoring between each loop should be composed. + {Qualifier, [CRs]} represents the composition of a list of composite refactorings into a new composite refactoring.

+ +

Macro Definitions

+In practice, instead of writing tuples with tags in a composite refactoring script, we use macros. A suite of macros +have been defined for this purpose as follows.

+ +

?interactive([ERs]) represents {interactive, atomic, [ERs]}.

+ +

?interactive(Qualifier,[ERs]) represents {interactive, Qualifier, [ERs]}.

+ +

?repeat_interactive([ERs]) represents {repeat_interactive, atomic, [ERs]}.

+ +

?repeat_interactive(Qualifier,[ERs]) represents {repeat_interactive, Qualifier, [ERs]}.

+ +

?if_then(Cond, CR) represents {if_then, fun()-> Cond end, CR}.

+ +

?while(Cond, CR) represents {while, fun() -> Cond end, atomic, CR}.

+ +

?while(Cond, Qualifier, CR) represents {while, fun() -> Cond end, Qualifier, CR}.

+ +

?try_refac([CRs]) represents {non_atomic, [CRs]}.

+ +

?refac([CRs]) represents {atomic, [CRs]}.

+ +

Tracking of Entity Names

+ In a composite refactoring, it is possible that a refactoring needs to refer to a program entity that might have be + renamed by previous refactoring steps. Tracking the change of names statically is problematic given the dynamic nature + of a refactoring process.Wrangler allows users to refer to a program entity through its initial name, i.e. the name of + the entity before the refactoring process is started. For this purpose, we have defined a macro ?current. An entity + name wrapped in a ?current macro tells Wrangler that this entity might have been renamed, therefore Wrangler needs to +search its record of renaming history, and replaces the macro application with the entity's latest name. If no renaming +history can be found for that entity, its original name is used.

+ +

In the background, Wrangler monitors application of renaming refactorings, and keeps a record of the mapping between + the old and new names. Currently, only module names and function names are tracked, as these are the entities that can + be referred by name and also can be renamed by the refactorings supported by Wrangler. Syntactically, a module name is + represented as an Erlang atom, and a function name is represented by a tuple consisting of the module name, function name + and arity. The data format returned by the application of the ?current is the same as its input.

+ + Some example composite refactorings: +
  • + Batch clone elimination. +
  • +
  • + Batch renaming of function names from camelCase to camel_case. +
  • +
  • + Add a prefix to Erlang module names. +
  • +
  • + Function to behaviour instance. +
  • +
  • + Expression to behaviour instance. +
  • +
  • + Unfold behaviour instance. +
  • +

    How to apply an own-defined composite refactoring

    + To invoke a user's own-defined gen_composite_refac refactoring, select menu item Wrangler -> Refactor -> Apply Composite Refactoring, +Wrangler will then prompt you to input the name of the callback module, and the values for parameters needed by the +refactoring.

    + +

    How to add an own-defined composite refactoring to the menu

    + To add a user-defined gen_composite_refac refactoring to the My gen_composite_refac Refacs menu, set the file buffer implementing the + refactoring as the current buffer, then select Wrangler -> Refactor -> Add to My gen_composite_refac Refacs.
    + + +

    Generated by EDoc, Nov 12 2015, 19:13:23.

    + + diff --git a/docs/doc/gen_refac.html b/docs/doc/gen_refac.html new file mode 100644 index 00000000..0c8f0d91 --- /dev/null +++ b/docs/doc/gen_refac.html @@ -0,0 +1,135 @@ + + + + +Module gen_refac + + + + +
    + +

    Module gen_refac

    +This module defines the gen_refac behaviour. + +

    This module defines the gen_refac behaviour.
    Required callback functions: input_par_prompts/0, select_focus/1, check_pre_cond/1, selective/0, transform/1.

    +

    Authors: Huiqing Li (H.Li@kent.ac.uk).

    + +

    Description

    This module defines the gen_refac behaviour. It provides a +high-level abstraction of the logic work-flow of a refactoring +process. A user-interactive refactoring +process in Emacs generally works in the following way : the user first +selects the focus of interest by either pointing the cursor to a +particular program entity or by highlighting, then invokes the +refactoring command; in case that the refactoring needs certain +initial inputs from the user, it will prompt the user to input +the values from the mini-buffer. After all these interactions, +the refactor engine starts the pre-condition checking to +make sure that performing the refactoring initiated by the user +will not change the behaviour of the program; the refactorer +continues to carry out the program transformation if the pre-condition +passes, otherwise aborts the refactoring process and returns the reason +for failure.

    + +

    The idea behind this module is that the user module provides functions + to handle different parts of the refactoring process that is particular + to that refactoring, while gen_refac handles the parts that are common +to all refactorings.

    + + The user module should export: +
         input_par_prompts()
    +       ===> [string()]
    + input_par_prompts returns the list of prompt strings to be used when + the refactorer asks the user for input. There should be one + prompt string for each input. +
         select_focus(Args::#args{})
    +        ===> none|{ok, term()}|{error, Reason}
    + select_pars returns the focus of interest selected by the user. + This function should return none if no focus selection is needed; + {error, Reason} if the user didn't select the kind of entity + expected; or {ok, term() when a valid focus of interest has been + selected. +
          check_pre_cond(Args::#args{})
    +        ===> ok | {error, Reason}
    + This function checks whether the pre-conditions of the refactoring + hold, and returns ok if the pre-condition checking passes, otherwise + {error, Reason}. +
          selective()
    +        ===> true | false
    + This function should returns true if the user is allowed to browse + through and select the changes to be made. +
         transform(Args::#args())
    +       ===> {ok, [{{filename(),filename()} syntaxTree()}] | {error, Reason}}

    + Function transform carries out the transformation part of the + refactorings. If the refactoring succeeds, it returns the list of + file names together with their new AST (only files that have been + changed need to be returned); otherwise {error, Reason}.

    + + Record args defines the data structure that is passed through, and also modified by, the different phases + of the refactoring. +
          -record(args,{current_file_name :: filename(),         %% the file name of the current Erlang buffer.
    +                    cursor_pos        :: pos(),              %% the current cursor position.
    +                    highlight_range   :: {pos(), pos()},     %% the start and end location of the highlighted code if there is any.
    +                    user_inputs       :: [string()],         %% the data inputted by the user.
    +                    focus_sel         :: any(),              %% the focus of interest selected by the user.
    +                    selective         :: boolean(),          %% selective refactoring or not.
    +                    search_paths      ::[dir()|filename()],  %% the list of directories or files which specify the scope of the project.
    +                    tabwidth =8        ::integer()           %% the number of white spaces denoted by a tab key.
    +                   }).
    + +

    Some example refactorings implemented using the Wrangler API: +

  • + Swap arguments of a function;. +
  • +
  • + Remove an argument of a function;. +
  • +
  • + Replace the uses of lists:keysearch/3 with lists:keyfind/3; +
  • +
  • + Specialise a function definition; +
  • +
  • + Apply to remote function call; +
  • +
  • + Introduce an import attribute; +
  • +
  • + Remove an import attribute; +
  • +
  • + Batch renaming of function names from camelCaseto camel_case. +
  • +
  • + A collection of code inspectors written using the Wrangler API. +
  • + +

    How to apply an own-defined refactoring

    + To invoke a user's own-defined gen_refac refactoring, select menu item Wrangler -> Refactor -> Apply Adhoc Refactoring, +Wrangler will then prompt you to input the name of the callback module, and the values for parameters needed by the +refactoring.

    + +

    How to add an own-defined refactoring to the menu

    + To add a user-defined gen_refac refactoring to the My gen_refac Refacs menu, set the file buffer implementing the + refactoring as the current buffer, then select Wrangler -> Refactor -> Add to My gen_refac Refacs. + +

    Function Index

    + +
    run_refac/2The interface function for invoking a refactoring defined + in module ModName.
    + +

    Function Details

    + +

    run_refac/2

    +
    +

    run_refac(Module::module() | string() | tuple(), Args::[term()]) -> {ok, string()} | {change_set, [{string(), string()}], module(), #args{}} | {error, term()}

    +

    The interface function for invoking a refactoring defined + in module ModName.

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:22.

    + + diff --git a/docs/doc/how_to_use.htm b/docs/doc/how_to_use.htm index a714ceb0..8ad46c7b 100644 --- a/docs/doc/how_to_use.htm +++ b/docs/doc/how_to_use.htm @@ -1,7 +1,7 @@ - + How to use: refactorings diff --git a/docs/doc/index.html b/docs/doc/index.html new file mode 100644 index 00000000..c1f20b15 --- /dev/null +++ b/docs/doc/index.html @@ -0,0 +1,18 @@ + + + +The wrangler application + + + + + + + +<h2>This page uses frames</h2> +<p>Your browser does not accept frames. +<br>You should go to the <a href="overview-summary.html">non-frame version</a> instead. +</p> + + + diff --git a/docs/doc/inspec_examples.erl b/docs/doc/inspec_examples.erl new file mode 100644 index 00000000..5f17ef00 --- /dev/null +++ b/docs/doc/inspec_examples.erl @@ -0,0 +1,380 @@ + %% Copyright (c) 2010, Huiqing Li, Simon Thompson +%% All rights reserved. +%% +%% Redistribution and use in source and binary forms, with or without +%% modification, are permitted provided that the following conditions are met: +%% %% Redistributions of source code must retain the above copyright +%% notice, this list of conditions and the following disclaimer. +%% %% Redistributions in binary form must reproduce the above copyright +%% notice, this list of conditions and the following disclaimer in the +%% documentation and/or other materials provided with the distribution. +%% %% Neither the name of the copyright holders nor the +%% names of its contributors may be used to endorse or promote products +%% derived from this software without specific prior written permission. +%% +%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' +%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +%% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS +%% BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +%% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +%% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +%% OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +%% ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +%% +%%@hidden +%%@private +%%@author Huiqing Li +%% +%% +%%@doc +%% Some example code inspection functions using code templates. +%% +%% This module demonstrates how to use code templates and the predefined +%% macros, ?COLLECT and ?COLLECT_LOC, to collect information about specific +%% code fragments of interest. +%% To invoke a user-defined code inspection function from the `Inspector' menu, select +%% `Apply Adhoc Code Inspector' first, then Wrangler will prompt you to input the +%% the name of the module in which the code inspection function is defined, and +%% the code inspection function name; if the code inspection function requires +%% user-inputs, Wrangler will also prompt you to input the parameter values. After +%% that, the code inspection function will be run by Wrangler, and the results are +%% shown in the *erl-output* buffer. +%% +%% In order for a user-defined code inspection function to be invoked by the +%% `Apply Adhoc Code Inspector' command, a number of coding rules should be +%% followed by the code inspection function: +%% +%% -- The code inspection function should have an arity of 1; +%% +%% -- The code inspection function should have two function clauses: one +%% function clause takes atom `input_pars' as the parameter, and the other +%% takes record `args' as the parameter. If the code inspection function +%% does not require any user-inputs before hand, +%% the function clause with `input_pars' as the parameter should return an empty list, +%% otherwise it should return the list of prompt strings to be used when +%% the Wrangler asks the user for input, and there should be one prompt string +%% for each user-input. The `args' record taken as parameter by the other +%% function clause contains information that is passed to the code inspection +%% function. To be consistent, the definition of the `args' record is the same +%% as the one used by the `gen_refac' behaviour, although record fields `cursor_pos' +%% ,`highlight_range' and 'focus_sel' are generally not use by code inspection +%% functions. Here is the definition of record `args': +%% +%% ```-record(args,{current_file_name :: filename(), %% the file name of the current Erlang buffer. +%% cursor_pos :: pos(), %% the current cursor position. +%% highlight_range :: {pos(), pos()}, %% the start and end location of the highlighted code if there is any. +%% user_inputs :: [string()], %% the data inputted by the user. +%% focus_sel :: any(), %% the focus of interest selected by the user. +%% search_paths ::[dir()|filename()], %% the list of directories or files which specify the scope of the project. +%% tabwidth =8 ::integer() %% the number of white spaces denoted by a tab key. +%% }).''' +%% +%% -- In the case that the code inspection function returns location range information about +%% code fragments of interest, in order for the locations to be mouse-clickable, the +%% location range should be of the format: `{filename(), {pos(),pos()}}'. +%% +%% Source code for this module: +%% + +-module(inspec_examples). + +-include("../include/wrangler.hrl"). + +-export([top_level_if/1, + append_two_lists/1, + unnecessary_match/1, + non_tail_recursive_function/1, + is_non_tail_recursive/1, + calls_to_specific_function/1]). + +-export([test/1,test1/1,test2/1,test3/1,test4/1, test5/1]). + +-compile(export_all). + +-import(api_refac, [fun_define_info/1]). + +%%=================================================================== +%% In the current Erlang file, collects those function definitions +%% consisting of a single function clause that is an `if' expression, +%% and returns the MFA of each function definition detected. +%% Note: by including `Guard@@' in the template, this function will +%% collect functions both with guard expressions and without guard +%% expression (i.e. `Guard@@' is `[]'). + +-spec(top_level_if/1::(#args{}) ->[{modulename(), functionname(), arity()}]). +%% No user inputs needed. +top_level_if(input_par_prompts) -> + []; +top_level_if(_Args=#args{search_paths=SearchPaths})-> + ?FULL_TD_TU([?COLLECT(?T("f@(Args@@) when Guard@@ ->Body@."), + api_refac:fun_define_info(f@), + api_refac:type(Body@) == if_expr)], + SearchPaths). + +%%===================================================================== +%% Collects the uses of `lists:append/2' in the project, and returns +%% the location information of each application instance found. + +-spec(append_two_lists/1::(#args{}) ->[{filename(), {pos(),pos()}}]). +%% No user inputs needed. +append_two_lists(input_par_prompts) -> []; +append_two_lists(_Args=#args{search_paths=SearchPaths}) -> + ?STOP_TD_TU([?COLLECT(?T("F@(L1@, L2@)"), + {_File@, wrangler_misc:start_end_loc(_This@)}, + {lists, append, 2} == api_refac:fun_define_info(F@))], + SearchPaths). + +%%===================================================================== +%% Collects the uses of a specific function, and returns the location +%% information of each application instance found, and returns the +%% location information of each application instance found. + +%% Ask the user to input the MFA information of the function to check. +-spec(calls_to_specific_function/1::(#args{}) ->[{filename(), {pos(),pos()}}]). +calls_to_specific_function(input_par_prompts) -> + ["Module name: ", "Function name: ", "Arity: "]; + +calls_to_specific_function(_Args=#args{user_inputs=[M,F,A], + search_paths=SearchPaths}) -> + {M1, F1, A1}={list_to_atom(M), list_to_atom(F), list_to_integer(A)}, + ?FULL_TD_TU([?COLLECT_LOC(?FUN_APPLY(M1, F1, A1), true)], + SearchPaths). + + +%%=================================================================== +%% Collects clause bodies that ends in the format of `Var=Expr, Var', +%% and returns the location information of `Var=Expr, Var'. + +%% No user inputs are needed. +-spec(unnecessary_match/1::(#args{}) ->[{filename(), {pos(),pos()}}]). + +unnecessary_match(input_par_prompts) ->[]; + +%% Instead of collecting the location of the whole matching node, this +%% function only returns the location of the last two expressions; therefore +%% we cannot use the ?COLLECT_LOC macro. `_File@' is a meta variable +%% generated automatically to represent the name of the file to which +%% the matching code belong, and is visible to both the second and the third +%% arguments of the ?COLLECT macro. +%% When the collector returns the data collected in the format of +%% {File,{StartPos, EndPos}}, Wrangler will display the result in such a way +%% that the location information is mouse clickable. +unnecessary_match(_Args=#args{search_paths=SearchPaths}) -> + ?FULL_TD_TU([?COLLECT(?T("Body@@, V@=Expr@, V@"), + {_File@, wrangler_misc:start_end_loc(lists:nthtail(length(Body@@), _This@))}, + api_refac:type(V@) == variable)], + SearchPaths). + + +%%=================================================================== +%% Collects the recursive function definitions that are not tail-recursive, +%% and returns the MFA information of those functions. +-spec(non_tail_recursive_function/1::(#args{}) ->[{modulename(), functionname(), arity()}]). + +non_tail_recursive_function(input_par_prompts)-> []; +non_tail_recursive_function(_Args=#args{search_paths=SearchPaths}) -> + ?FULL_TD_TU([?COLLECT(?T("f@(Args@@@) when Guard@@@-> Body@@@."), + fun_define_info(f@), + is_non_tail_recursive(_This@))], + SearchPaths). + +%% Returns `true' if a recursive function definition is not tail recursive. +is_non_tail_recursive(FunDef) -> + MFA= fun_define_info(FunDef), + Cond= fun(This, Last) -> + AllApps=collect_apps(This,MFA), + LastApps=collect_last_apps(Last, MFA), + SimpleExprs=collect_simple_exprs(Last), + EnclosedApps=apps_enclosed_in_simple_exprs(LastApps,SimpleExprs), + LastExprLoc=wrangler_misc:start_end_loc(Last), + AllApps /= [] andalso (AllApps--[LastExprLoc]/= LastApps + orelse EnclosedApps /= []) + end, + %% collect each function clause that is not tail recursive. + Res=?FULL_TD_TU([?COLLECT(?T("f@(Args@@) when Guard@@ -> Body@@, Last@;"), + true, + Cond(_This@, Last@))], + FunDef), + %% A function is not tail-recursive if any of its function + %% clause is recursive, but not tail-recursive. + lists:member(true, Res). + +%% collect all the function application instances of +%% a specific function. +collect_apps(FunDef, MFA) -> + ?FULL_TD_TU([?COLLECT(?T("F@(Args@@)"), + wrangler_misc:start_end_loc(_This@), + fun_define_info(F@) == MFA)], + FunDef). + +%% collect all the last clause body expressions that +%% are function applications. +collect_last_apps(Last, MFA) -> + ?FULL_TD_TU([?COLLECT(?T("Body@@, F@(Args@@)"), + wrangler_misc:start_end_loc(lists:last(_This@)), + fun_define_info(F@)==MFA + )], + Last). +%% collect all the expressions that is part of `LastExpr', but +%% is not a `case'/`if'/`receive'/`block'/'parentheses' expression. +collect_simple_exprs(LastExpr) -> + ?FULL_TD_TU([?COLLECT(?T("E@"), + wrangler_misc:start_end_loc(E@), + api_refac:is_expr(E@) andalso + not (lists:member(api_refac:type(E@), + [case_expr, receive_expr, + if_expr,parentheses, + block_expr])) + ) + ], + LastExpr). + +%% returns the subset of `Apps' that each of which is +%% locationally enclosed by at least one member of `Exprs'. +apps_enclosed_in_simple_exprs(Apps, Exprs) -> + lists:filter(fun(AppLoc) -> + lists:any(fun(ExprLoc) -> + enclose(ExprLoc, AppLoc) + end,Exprs) + end, Apps). + +%% returns `true' is location `Loc1' is enclosed by +%% location location `Loc', but only equal to `Loc2'. +enclose(_Loc1={Start1, End1},_Loc2={Start2,End2}) -> + (Start1 =< Start2 andalso End2 < End1) orelse + (Start1 < Start2 andalso End2 =< End1). + + +%%=================================================================== +%% Collects all function clauses whose clause body have a sequence of +%% two or more expressions. +%%@private +test(input_par_prompts)-> + []; +test(_Args=#args{search_paths=SearchPaths}) -> + ?FULL_TD_TU([?COLLECT(?T("f@(Args@@) when Guard@@-> First@, Second@,Body@@;"), + api_refac:fun_define_info(f@), + true)], + SearchPaths). + + +%%=================================================================== +%% Collects all functions, and returns the MFA info of each function. +%%@private +test1(input_par_prompts)-> + []; +test1(_Args=#args{search_paths=SearchPaths}) -> + ?FULL_TD_TU([?COLLECT(?T("f@(Args@@@) when Guard@@@-> Body@@@."), + api_refac:fun_define_info(f@), + true)], + SearchPaths). + +%%=================================================================== +%% Collects all function clauses, and returns the MFA info of each +%% function clause collected. +%%@private +test2(input_par_prompts)-> + []; +test2(_Args=#args{search_paths=SearchPaths}) -> + ?FULL_TD_TU([?COLLECT(?T("f@(Args@@)when Guard@@-> Body@@;"), + api_refac:fun_define_info(f@), + true)], + SearchPaths). + +%%=================================================================== +%% Collects all function clause without guards, and returns the MFA +%% info of each function clause collected. +%%@private +test3(input_par_prompts)-> + []; +test3(_Args=#args{search_paths=SearchPaths}) -> + ?FULL_TD_TU([?COLLECT(?T("f@(Args@@)-> Body@@;"), + api_refac:fun_define_info(f@), + true)], + SearchPaths). + + +%%@private +test4(input_par_prompts) -> + []; +test4(_Args=#args{search_paths=SearchPaths}) -> + ?FULL_TD_TU([?COLLECT(?T("case lists:keysearch(Key@, N@, TupleList@) of + Pats@@@ when Guards@@@ -> + Body@@@ + end"), + {_File@, wrangler_misc:start_end_loc(_This@)}, + true), + ?COLLECT(?T("f@(Args@@) when Guard@@ ->Body@."), + api_refac:fun_define_info(f@), + api_refac:type(Body@) == if_expr)], + SearchPaths). + + + +test5(input_par_prompts)-> + []; +test5(_Args=#args{current_file_name=CurFileName}) -> + ?FULL_TD_TU([?COLLECT_LOC(?T("[1,2,F@]"), + true)], + [CurFileName]). + + +find_map_like_dict(input_par_prompts) -> + []; +find_map_like_dict(_Args=#args{search_paths=SearchPaths}) -> + ?FULL_TD_TU( + [?COLLECT( + ?T("F@(Args@@)"), + {_File@, api_refac:start_end_loc(_This@)}, + lists:member( + api_refac:fun_define_info(F@), + map_like_dict()) + )], + SearchPaths). + + +find_non_map_like_dict(input_par_prompts) -> + []; +find_non_map_like_dict(_Args=#args{search_paths=SearchPaths}) -> + ?FULL_TD_TU( + [?COLLECT( + ?T("F@(Args@@)"), + {_File@, api_refac:start_end_loc(_This@)}, + lists:member( + api_refac:fun_define_info(F@), + non_map_like_dict()) + )], + SearchPaths). + +map_like_dict() -> + [{dict,new,0}, + {dict,is_key,0}, + {dict,to_list,1}, + {dict,from_list,1}, + {dict,size,1}, + {dict,is_empty,1}, + {dict,fetch,2}, + {dict,find,2}, + {dict,fetch_keys,1}, + {dict,erase,2}, + {dict,store, 3}, + {dict,fold,3}, + {dict,map,3}]. + +non_map_like_dict() -> + [{dict,append,3}, + {dict,append_list,3}, + {dict,update,3}, + {dict,update,4}, + {dict,update_counter,3}, + {dict,filter,2}, + {dict,merge,3}]. + + diff --git a/docs/doc/inspec_lib.html b/docs/doc/inspec_lib.html new file mode 100644 index 00000000..beca8024 --- /dev/null +++ b/docs/doc/inspec_lib.html @@ -0,0 +1,199 @@ + + + + +Module inspec_lib + + + + +
    + +

    Module inspec_lib

    +This module describes the code inspection functions + that are currently supported by Wrangler. +

    Copyright © 2006-2011 Huiqing Li, Simon Thompson +

    + +

    Authors: Huiqing Li, Simon Thompson [web site: http://www.cs.kent.ac.uk/projects/wrangler].

    + +

    Description

    This module describes the code inspection functions + that are currently supported by Wrangler. +

    Data Types

    + +

    col()

    +

    col() = integer()

    + + +

    dir()

    +

    dir() = string()

    + + +

    filename()

    +

    filename() = string()

    + + +

    functionarity()

    +

    functionarity() = integer()

    + + +

    functionname()

    +

    functionname() = atom()

    + + +

    line()

    +

    line() = integer()

    + + +

    modulename()

    +

    modulename() = atom()

    + + +

    pos()

    +

    pos() = {integer(), integer()}

    + + +

    Function Index

    + + + + + + + + + + + + +
    calls_to_fun/4Report the functions by which the function specified is called.
    cyclic_dependent_modules/3Report the cyclic module dependencies, if there is any, for a given list of + directories of Erlang source code.
    dependencies_of_a_module/2Report modules that depend on the module specified, as well as modules on which the + module specified in dependent.
    find_var_instances/3Find all the instances of a variable, including both defining and use instances.
    gen_function_callgraph/3Generate the function callgraph for a given Erlang file.
    gen_module_graph/3Generate the module graph for a given list of directories of Erlang source code.
    improper_inter_module_calls/2Report improper module dependencies, if there is any, for a given list of + directories of Erlang source code.
    large_modules/2Report all the modules that consist of more than a specified number of lines of code.
    long_functions/2Report all the functions that consist of more than specified number of lines of code.
    nested_exprs/3Find all the functions that contain certain type of expressions that are nested a + specified number of levels or more.
    non_tail_recursive_servers/1Report non tail-recursive server functions.
    not_flush_unknown_messages/1Report functions whose receive expression, if there is one, does not flush unknown messages.
    + +

    Function Details

    + +

    calls_to_fun/4

    +
    +

    calls_to_fun(FileName::filename(), FunctionName::functionname(), Arity::integer(), SearchPaths::[dir()]) -> {error, string()} | ok

    +

    Report the functions by which the function specified is called. A function is reported + only if Wrangler is certain that it calls the function specified.

    + +

    cyclic_dependent_modules/3

    +
    +

    cyclic_dependent_modules(OutputDotFileName::filename(), SearchPaths::[filename() | dir()], WithLabel::boolean()) -> true

    +

    Report the cyclic module dependencies, if there is any, for a given list of + directories of Erlang source code.

    + +

    dependencies_of_a_module/2

    +
    +

    dependencies_of_a_module(ModOrFileName::modulename() | filename(), SearchPaths::[filename() | dir()]) -> ok

    +

    Report modules that depend on the module specified, as well as modules on which the + module specified in dependent.

    + +

    find_var_instances/3

    +
    +

    find_var_instances(FileName::filename(), X2::{Line::integer(), Col::integer()}, TabWidth::integer()) -> {error, string()} | {ok, [{pos(), pos()}], [pos()]}

    +

    Find all the instances of a variable, including both defining and use instances.

    + +

    gen_function_callgraph/3

    +
    +

    gen_function_callgraph(OutputDotFileName::filename(), FileName::filename(), SearchPaths::[filename() | dir()]) -> true

    +

    Generate the function callgraph for a given Erlang file.

    + +

    gen_module_graph/3

    +
    +

    gen_module_graph(OutputDotFileName::filename(), SearchPaths::[filename() | dir()], WithLabel::boolean()) -> true

    +

    Generate the module graph for a given list of directories of Erlang source code.

    + +

    improper_inter_module_calls/2

    +
    +

    improper_inter_module_calls(OutputDotFileName::filename(), SearchPaths::[filename() | dir()]) -> true

    +

    Report improper module dependencies, if there is any, for a given list of + directories of Erlang source code.

    + +

    large_modules/2

    +
    +

    large_modules(SearchPaths::[dir()], Lines::integer()) -> {error, string()} | ok

    +

    Report all the modules that consist of more than a specified number of lines of code.

    + +

    long_functions/2

    +
    +

    long_functions(FileOrDirNames::[filename() | dir()], Lines::integer()) -> {error, string()} | ok

    +

    Report all the functions that consist of more than specified number of lines of code.

    + +

    nested_exprs/3

    +
    +

    nested_exprs(FileOrDirNames::[filename() | dir()], NestLevel::integer(), ExprType::'if' | 'case' | 'receive') -> {error, string()} | ok

    +

    Find all the functions that contain certain type of expressions that are nested a + specified number of levels or more.

    + +

    non_tail_recursive_servers/1

    +
    +

    non_tail_recursive_servers(FileOrDirNames::[filename() | dir()]) -> ok

    +

    Report non tail-recursive server functions. +

    + The Erlang Programming Rules says: + All servers must be tail-recursive, otherwise the server will consume memory until the system runs out of it. + + Don't program like this: + +

          loop() ->
    +        receive
    +          {msg1, Msg1} ->
    +            ...,
    +            loop();
    +          stop ->
    +            true;
    +          Other ->
    +            error_logger:log({error, {process_got_other, self(), Other}}),
    +            loop()
    +        end,
    +        io:format("Server going down").
    + 
    +  The above is not tail-recusive. This is a correct solution:
    + 
    +      loop() ->
    +        receive
    +          {msg1, Msg1} ->
    +            ...,
    +            loop();
    +          stop ->
    +            io:format("Server going down");
    +          Other ->
    +            error_logger:log({error, {process_got_other, self(), Other}}),
    +            loop()
    +        end.
    +

    + +

    not_flush_unknown_messages/1

    +
    +

    not_flush_unknown_messages(FileOrDirNames::[filename() | dir()]) -> ok

    +

    Report functions whose receive expression, if there is one, does not flush unknown messages. +

    + The Erlang Programming Rules says: + Every server should have an Other alternative in at least one receive statement. + This is to avoid filling up message queues. Example: + +

          main_loop() ->
    +        receive
    +          {msg1, Msg1} ->
    +            ...,
    +            main_loop();
    +          {msg2, Msg2} ->
    +            ...,
    +            main_loop();
    +          Other -> % Flushes the message queue.
    +            error_logger:error_msg(
    +                "Error: Process ~w got unknown msg ~w~n.",
    +                [self(), Other]),
    +            main_loop()
    +        end.
    +

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:22.

    + + diff --git a/docs/doc/keysearch_keyfind.erl b/docs/doc/keysearch_keyfind.erl new file mode 100644 index 00000000..909bd039 --- /dev/null +++ b/docs/doc/keysearch_keyfind.erl @@ -0,0 +1,19 @@ +%%@hidden +%%@private +-module(keysearch_keyfind). + +-export([old_api_module_name/0]). + +-compile(export_all). + +old_api_module_name() -> + lists. + +keysearch(Key, N, TupleList) -> + case lists:keyfind(Key, N, TupleList) of + Tuple when is_tuple(Tuple)-> + {value, Tuple}; + false -> + false + end. + diff --git a/docs/doc/modules-frame.html b/docs/doc/modules-frame.html new file mode 100644 index 00000000..99de5c06 --- /dev/null +++ b/docs/doc/modules-frame.html @@ -0,0 +1,20 @@ + + + +The wrangler application + + + +

    Modules

    + + + + + + + + + +
    api_interface
    api_refac
    api_wrangler
    gen_composite_refac
    gen_refac
    inspec_lib
    refac_api_migration
    wrangler_gen
    wrangler_refacs
    + + \ No newline at end of file diff --git a/docs/doc/overview-summary.html b/docs/doc/overview-summary.html new file mode 100644 index 00000000..07204c7c --- /dev/null +++ b/docs/doc/overview-summary.html @@ -0,0 +1,421 @@ + + + + +Wrangler - an Erlang Refactoring Tool + + + + +

    Wrangler - an Erlang Refactoring Tool

    +

    Copyright © 2006-2012 Huiqing Li, Simon Thompson

    +

    Authors: Huiqing Li (H.Li@kent.ac.uk), Simon Thompson (s.j.thompson@kent.ac.uk) [web site: http://www.cs.kent.ac.uk/projects/wrangler].

    +

    Wrangler is an Erlang refactoring tool that supports interactive +refactoring of Erlang programs.

    + +

    Contents

    + +
      +
    1. Introduction
    2. +
    3. The Interface of Wrangler
    4. +
    5. Support for Macros
    6. +
    7. Refactoring Code with Syntax Errors
    8. +
    9. Download
    10. +
    11. How to Use Wrangler
    12. +
    13. References
    14. +
    15. Acknowledgments
    16. +
    + +

    Introduction

    + +

    Refactoring is the process of improving the design of a program without +changing its external behaviour. While refactoring by hand is possible, tool +support for refactoring is invaluable as it is more reliable, and allows +refactoring to be done (or undone) easily. Wrangler is such a tool that +supports interactive refactoring of Erlang programs. Wrangler currently +supports a number of basic Erlang refactorings, such as renaming of +variable/function/module names, generalisation of a function definition, +function extraction, folding against a function definition, duplicated code +detection, etc.

    + +

    Wrangler also provides a set of process-based refactorings, including the + introduction of process naming, instead of providing access to a process +only through a dynamically-generated process id Wrangler also contains +a variety of refactorings which work with Erlang QuickCheck, introducing + and merging constructs such as ?LET and ?FORALL.

    + +

    Transforming data types in Erlang can be difficult, as Erlang functions +can take values of any type, in principle. There are situations -- particularly +in implementing an Erlang behaviour , which can be thought of as an +interface for a set of callback functions -- where the types are more +constrained, and where data transformations are possible. In particular +we have implemented transformations for state data in various kinds +of generic state machine in both the OTP library and QuickCheck.

    + +

    In implementing Wrangler we have chosen to respect various features of +the language and related tools. Wrangler is able to process modules which +use macros, including the Erlang test frameworks that are in +regular use. Wrangler also respects the naming conventions in those +test frameworks.

    + +

    Wrangler provides a portfolio of decision support tools. The code inspector +highlights local code smells and a number of reports highlight issues in +the module structure of projects, including circular inclusions and other +potential faults. The code clone detection facilities can be +used on large multi-module projects to report on code clones and how they +can be removed; clone detection can be preformed incrementally on larger code +bases, for example as part of a continuous integration approach to software +construction.

    + + +

    Wrangler has recently been extended with a framework that allows users to define +for themselves refactorings and code inspection functions that suit their +needs. These are defined using a template- and rule-based +program transformation and analysis API. Wrangler also supports a +domain-specific language that allows users to script composite refactorings, +test them and apply them on the fly. +User-defined refactorings and scripts are not second-class citizens: like +the existing Wrangler refactorings, user-defined refactorings benefit +from features such as results preview, layout preservation, selective +refactoring, undo and so on.

    + + +

    Built on top of the functionalities provided by the Erlang syntax-tools +package, Wrangler is embedded in the Emacs/Xemacs editing environment, and +makes use of the functionalities provided by Distel, an Emacs-based user +interface toolkit for Erlang, to manage the communication between the +refactoring tool and Emacs. Wrangler is also integrated within +Eclipse, as a part of the ErlIDE plugin for Erlang.

    + +

    The Interface of Wrangler

    + +

    Wrangler in Emacs

    +Below is a snapshot of Wrangler embedded in Emacs, which shows a particular +refactoring scenario. The user has selected the expression +io:format("Hello") in the definition of repeat/1 , has +chosen the Generalise Function Definition command from the +Refactor sub-menu, and has just entered a new parameter name A in the +mini-buffer.

    + +

    selecting a refactoring from the Emacs menu

    + +

    The result of this refactoring is shown in the snapshot below.

    + +

    Emacs buffers after running the refactoring

    + +

    Preview of the changes to be made by a refactoring is supported, and the +user could choose to commit or abort the refactoring result after preview. +Wrangler's preview uses the Ediff package for Emacs.

    + +

    All the implemented refactorings are module-aware. In the case that a +refactoring affects more than one module in the program, a message telling +which files have been modified by the refactorer will be given after the +refactoring has been successfully done. The Customize Wrangler +command from the Refactor sub-menu allows the user to specify the +boundary of the program, i.e., the directories that will be searched and +analysed by the refactorer, as shown in the example snapshot below.

    + +

    customizing Wrangler behaviour in Emacs

    + +

    Undo is supported by the refactorer. Applying undo once will revert +the program back to the status right before the last refactoring performed. +However, PLEASE NOTE that the refactorer undo is currently separate +from the Emacs undo, and undoing a refactoring will lose all the editing +activities after the refactoring.

    + +

    Wrangler in Eclipse

    +Below is a snapshot of Wrangler embedded in Eclipse + Erlide.

    + +

    snapshot of Wrangler embedded in Eclipse with Erlide

    + +

    Support for Macros

    + +

    Wrangler makes use of functionalities provided by the epp_dodger module +from the Erlang syntax_tools library to parse Erlang source code, and +should be able to refactor Erlang modules containing preprocessor directives +and macro applications, as long as the macro definitions are syntactically +"well-behaved".

    + +

    Refactoring Code with Syntax Errors

    + +

    Wrangler accepts Erlang programs with syntax errors or macro definitions +that cannot be parsed by epp_dodger. In the case that the program under +consideration has syntax errors or unparsable macros, functions/attributes +to which these syntax errors belong are not affected by the refactoring +process; however, warning messages asking for manual inspection of those +parts of the program are given after the refactoring.

    + +

    Download

    + +

    Wrangler is downloadable from Github: https://github.com/RefactoringTools, and also +from http://www.cs.kent.ac.uk/projects/wrangler

    + +

    How to Use Wrangler

    + +
      +
    1. Open an Erlang source file in the Emacs editor. You should now have a + menu called Erlang, if you have configured Emacs properly to +use the Erlang-mode (see the file INSTALL otherwise).

      + +
    2. +
    3. To start Wrangler, type: M-x erlang-wrangler-on, or + alternatively Ctrl-c Ctrl-r. After that, new menu Wrangler should appear in the +menu bar (see INSTALL otherwise).

      + +
    4. +
    5. To stop Wrangler, type M-x erlang-wrangler-off, or + alternatively use Ctrl-c Ctrl-r again. The Refactor and Inspector +menus will disappear from the menu bar.

      + +
    6. +
    7. You can use Ctrl-c Ctrl-r to toggle Wrangler on or off.

      + +
    8. +
    9. For most refactorings, the editor interface will pass the current +filename (should be the module name, as well), the refactoring command, +and the current cursor position. For some refactorings, you'll also +need to highlight an expression, or enter a new name.

      + +
    10. +
    11. The Customize Wrangler menu in the Wrangler submenu allows you +to specify the boundary of the system by giving the list of directories +to search for Erlang source files/header files that could be affected +by a refactoring.

      + +
    12. +
    13. For most refactorings, the editor interface will pass the current filename +(should be the module name, as well), the refactoring command, and the current +cursor position. For some refactorings, you'll also need to highlight an +expression, or enter a new name.

      + + How to use: + +
    14. +
    +
      + Extensions: + +
    + +

    References

    + +Our Refactoring +Functional Programs project website contains more information and +references about refactoring functional, especially Haskell, programs; and +our progress and ideas about refactoring Erlang programs are available at +our Wrangler project +webpage. Here are some publications related to Wrangler: + + +

    Acknowledgments

    + +The work was initially supported by EPSRC in the UK, and is now by the +European Commission. We are very grateful that we were able to build the +tool on top of Distel +and +Erlang +SyntaxTools, and make use some of the ideas from +Dialyzer. + +
    + +

    Generated by EDoc, Nov 5 2015, 16:30:22.

    + + diff --git a/docs/doc/refac_add_an_import_attribute.erl b/docs/doc/refac_add_an_import_attribute.erl new file mode 100644 index 00000000..82448db5 --- /dev/null +++ b/docs/doc/refac_add_an_import_attribute.erl @@ -0,0 +1,124 @@ +%% Copyright (c) 2013, Huiqing Li, Simon Thompson +%% All rights reserved. +%% +%% Redistribution and use in source and binary forms, with or without +%% modification, are permitted provided that the following conditions are met: +%% %% Redistributions of source code must retain the above copyright +%% notice, this list of conditions and the following disclaimer. +%% %% Redistributions in binary form must reproduce the above copyright +%% notice, this list of conditions and the following disclaimer in the +%% documentation and/or other materials provided with the distribution. +%% %% Neither the name of the copyright holders nor the +%% names of its contributors may be used to endorse or promote products +%% derived from this software without specific prior written permission. +%% +%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' +%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +%% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS +%% BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +%% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +%% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +%% OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +%% ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +%%@author Huiqing Li +%%@doc This module shows how to write refactorings +%% use the Wrangler API. + +%% The refactoring implemented in this module adds an +%% import attribute which explicitly imports the +%% functions which are defined in a user specified +%% module, and used in the current module by remote +%% function calls. +%% @hidden +%% @private +-module(refac_add_an_import_attribute). + +-behaviour(gen_refac). + +%% export of callback function. +-export([input_par_prompts/0, select_focus/1, + check_pre_cond/1, selective/0, + transform/1]). + +-include("../../include/wrangler.hrl"). + +%% Ask the user which module to import. +-spec (input_par_prompts/0::() -> [string()]). +input_par_prompts() -> + ["Module name:"]. + +%% no focus selection is needed. +-spec (select_focus/1::(#args{}) -> {ok, syntaxTree()}|{ok, none}). +select_focus(_Args) -> + {ok, none}. + +%% Pre-condition checking. +-spec (check_pre_cond/1::(#args{}) -> ok | {error, term()}). +check_pre_cond(Args=#args{user_inputs=[ModuleName]}) -> + case collect_uses(Args) of + [] -> + Msg =io_lib:format( + "There is no remote calls to " + "functions from module '~s'.", + [ModuleName]), + {error, lists:flatten(Msg)}; + _-> ok + end. + +selective() -> + false. + +%%Do the actual program transformation here. +-spec (transform/1::(args()) -> {ok, [{{filename(), filename()}, syntaxTree()}]}). +transform(Args=#args{current_file_name=File, + user_inputs=[ModuleName]}) -> + %% collect the functions that are defined + %% in ModuleNaem, and are remotely called + %% in the current module. + FAs=lists:usort(collect_uses(Args)), + FAs1 = api_refac:imported_funs(File, ModuleName), + %% Functions that need to be imported. + FunsToImport=FAs--FAs1, + {ok,AST} = api_refac:get_ast(File), + case FunsToImport of + [] -> + {ok, [{_, NewAST}]}=?FULL_TD_TP([rule(Args)], [{File, AST}]), + {ok, [{{File, File}, NewAST}]}; + _ -> + Import=make_import_attr(ModuleName, FunsToImport), + AST1=api_refac:insert_an_attr(AST,Import), + {ok, [{_,NewAST}]}=?FULL_TD_TP([rule(Args)], [{File, AST1}]), + {ok, [{{File, File}, NewAST}]} + end. + +collect_uses(_Args=#args{current_file_name=File, + user_inputs=[ModuleName]}) -> + ?FULL_TD_TU([?COLLECT(?T("M@:F@(Args@@)"), + {list_to_atom(?PP(F@)), length(Args@@)}, + ?PP(M@)==ModuleName)], + [File]). + +rule(_Args=#args{user_inputs=[ModuleName]}) -> + ?RULE(?T("M@:F@(Args@@)"),?TO_AST("F@(Args@@)"), + ?PP(M@)==ModuleName). + +make_import_attr(ModuleName, FAs) -> + ?TO_AST("-import("++ModuleName++","++ + format_fa_list(FAs)++")."). + +%% format_fa_list([]) -> +%% "[]"; +format_fa_list(FAs) -> + "["++lists:flatten(format_fas(FAs))++"]". + +format_fas([]) -> + ""; +format_fas([{F,A}]) -> + io_lib:format("~p/~p", [F,A]); +format_fas([{F,A}|T]) -> + io_lib:format("~p/~p,", [F,A]) ++ + format_fas(T). diff --git a/docs/doc/refac_api_migration.html b/docs/doc/refac_api_migration.html new file mode 100644 index 00000000..ab2a8041 --- /dev/null +++ b/docs/doc/refac_api_migration.html @@ -0,0 +1,118 @@ + + + + +Module refac_api_migration + + + + +
    + +

    Module refac_api_migration

    +Wrangler's support for API migration. + +

    Authors: Huiqing Li and Simon Thompson (H.Li, S.J.Thompson@kent.ac.uk).

    + +

    Description

    Wrangler's support for API migration. +Most software evolves during its lifetime, and this will often change +the API of a library. A change of interface made to a library function could +potentially affect all client applications of the library. The API +transformations required tend to be done manually by the maintainers +of the client code, and this process can be both tedious and error-prone.

    + +

    Wrangler's support for API migration refactorings is based on the template- + and rule-based technique; however, unlike general refactorings, an API migration + refactoring only requires the author to define adapter functions that implement + the old API functions using the new API functions. Once the adapter module +has been defined, Wrangler can then take this as input, and generate the refactoring +code that implements the migration.

    + +

    As a design principle, we try to limit the scope of changes as much as possible, so + that only the places where the old API function is called are affected, and +the remaining part of the code is unaffected.

    + +

    To illustrate our approach, we take the migration from regexp:match/2 + to re:run/3 as an example, which represents one of the most complex API changes +we have seen in practice. Tthe change involves every aspect of the function interface, +namely the module name, function name, arguments and values returned.

    + + An adapter function is a single-clause function that implements the old API + function using the new API. The function shown below is the adapter function for + the migration from regexp:match/2 to re:run/3. +
          match(String, RegExp) ->
    +        case re:run(String, RegExp, [global]) of
    +          {match, Match} ->
    +            {Start0, Len}=lists:last(lists:ukeysort(2, Match)),
    +            Start = Start0+1,
    +            {match, Start, Len};
    +          nomatch -> nomatch
    +        end.

    + A case expression is needed by the definition of the adapter function if and only + if the value returned by the API function is affected by the migration, and the returned + value is of a union type, i.e. a type consists of a number of alternatives. Within + the case expression, each expression clause handles one possible alternative of the + return value, and the clause body defines how to derive the value that should be returned + by the old API function from the value returned by the new one.

    + + A guard expression can be used to enures the mutual exclusiveness of expression clauses. For + example, the adaptor function for the migration from lists:keysearch/3 to lists:keyfind/3 can + be defined as: +
          keysearch(Key, N, TupleList) ->
    +        case lists:find(Key, N, TupleList) of
    +           Tuple when is_tuple(Tuple)->
    +               {value, Tuple};
    +           false ->
    +              false
    +        end.
    + +

    Obviously, for an API migration that does not affect the return value of the function, + a case expression is not needed. For the case in which only the name of the API function + has been changed, the body of the adapter function could be just a function application + of the new function.

    + + A number of constraints should be satisfied by adapter functions: +

    + Apart from the adaptor functions, an adaptor module should also export a special function + old_api_module_name/0 which returns an atom representing the name of the module to +which the old API functions belong. As a result, an adaptor module can only contain adaptor +functions for API functions from the same module.

    + + Some example adaptor modules: + +

    Function Index

    + + +
    do_api_migration/5
    generate_rule_based_api_migration_mod/2
    + +

    Function Details

    + +

    do_api_migration/5

    +
    +

    do_api_migration(FileOrDirs::[filename() | dir()], CallBackMod::module(), SearchPaths::[filename() | dir()], Editor::atom(), TabWidth::integer()) -> {error, string()} | {ok, [{filename(), filename(), string()}]}

    +
    + +

    generate_rule_based_api_migration_mod/2

    +
    +

    generate_rule_based_api_migration_mod(FileName::filename(), NewModName::string() | atom()) -> {ok, filename()} | {error, term()}

    +
    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:21.

    + + diff --git a/docs/doc/refac_apply_to_remote_call.erl b/docs/doc/refac_apply_to_remote_call.erl new file mode 100644 index 00000000..d13c27be --- /dev/null +++ b/docs/doc/refac_apply_to_remote_call.erl @@ -0,0 +1,88 @@ +%% Copyright (c) 2013, Huiqing Li, Simon Thompson +%% All rights reserved. +%% +%% Redistribution and use in source and binary forms, with or without +%% modification, are permitted provided that the following conditions are met: +%% %% Redistributions of source code must retain the above copyright +%% notice, this list of conditions and the following disclaimer. +%% %% Redistributions in binary form must reproduce the above copyright +%% notice, this list of conditions and the following disclaimer in the +%% documentation and/or other materials provided with the distribution. +%% %% Neither the name of the copyright holders nor the +%% names of its contributors may be used to endorse or promote products +%% derived from this software without specific prior written permission. +%% +%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' +%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +%% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS +%% BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +%% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +%% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +%% OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +%% ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +%%@author Huiqing Li +%%@hidden +%%@private +-module(refac_apply_to_remote_call). + +-behaviour(gen_refac). + +-export([input_par_prompts/0, select_focus/1, + check_pre_cond/1, selective/0, + transform/1]). + +-include("../../include/wrangler.hrl"). + +%% The Emacs mini-buffer prompts for the user input parameters. +-spec (input_par_prompts/0::() -> [string()]). +input_par_prompts() -> []. + +%% Select the focus of interest. If no selection is neeeded, +%% then return {ok, none}. +-spec (select_focus/1::(#args{}) -> {ok, syntaxTree()}|{ok, none}). +select_focus(_Args) ->{ok, none}. + +%% Pre-condition checking to ensure that the refactoring preserves the +%% behaviour of the program. +-spec (check_pre_cond/1::(#args{}) -> ok). +check_pre_cond(_Args) -> + ok. + +selective() -> + true. + +%%Do the actual program transformation here. +-spec (transform/1::(#args{}) -> {ok, [{{filename(), filename()}, syntaxTree()}]}|{error, term()}). +transform(_Args=#args{search_paths=SearchPaths})-> + ?FULL_TD_TP([rule(), + rule1(), + rule2() + ], SearchPaths). + +rule() -> + ?RULE(?T("Op@(N@@, M@, F@, [Args@@])"), + ?TO_AST("M@:F@(Args@@)"), + {erlang,apply,3} == api_refac:fun_define_info(Op@)). + +rule1() -> + ?RULE(?T("Op@(N@@, M@, F@, [])"), + ?TO_AST("M@:F@()"), + {erlang,apply,3} == api_refac:fun_define_info(Op@)). + +rule2() -> + ?RULE(?T("Op@(Fun@, [Args@@])"), + begin + {M,F,_A} = api_refac:fun_define_info(Fun@), + ?TO_AST(atom_to_list(M)++":"++atom_to_list(F)++"(Args@@)") + end, + case api_refac:fun_define_info(Fun@) of + {_,_,_}-> + true; + _ -> + false + end). + diff --git a/docs/doc/refac_batch_clone_elimination.erl b/docs/doc/refac_batch_clone_elimination.erl new file mode 100644 index 00000000..16b150de --- /dev/null +++ b/docs/doc/refac_batch_clone_elimination.erl @@ -0,0 +1,82 @@ +%%@hidden +%%@private +-module(refac_batch_clone_elimination). + +-export([composite_refac/1, input_par_prompts/0, select_focus/1]). + +-include("../../include/wrangler.hrl"). + +-behaviour(gen_composite_refac). + +input_par_prompts() -> + []. + +select_focus(_Args=#args{current_file_name=File, + cursor_pos=Pos}) -> + api_interface:pos_to_fun_def(File, Pos). + +composite_refac(_Args=#args{ + current_file_name = File, + focus_sel=FunDef, + search_paths=SearchPaths}) -> + {M,F,A} = api_refac:fun_define_info(FunDef), + ?atomic([?interactive( + ?refac_(rename_fun, + [M, {F, A}, + {user_input, fun(_)-> + "New funcion name: " + end}, + SearchPaths])), + ?refac_(rename_var, + [M, + begin + {_, F1, A1} = ?current(M,F,A), + {F1, A1} + end, + fun(X) -> + re:run(atom_to_list(X), "NewVar*")/=nomatch + end, + {user_input, fun({_, _, V}) -> + lists:flatten(io_lib:format( + "Rename variable ~p to: ", [V])) + end}, + SearchPaths]), + ?repeat_interactive( + ?refac_(swap_args, + [M, + begin + {_, F1, A1} = ?current(M,F,A), + {F1, A1} + end, + {user_input, fun(_)->"Index 1: " end}, + {user_input, fun(_)->"Index 2: " end}, + SearchPaths])), + ?if_then(not api_refac:is_exported(begin + {_, F1, A1} = ?current(M,F,A), + {F1, A1} + end, File), + ?interactive( + ?refac_(add_to_export, [File, begin + {_, F1, A1} = ?current(M,F,A), + {F1, A1} + end, SearchPaths]))), + ?non_atomic(?refac_(fold_expr, + [{file, fun(_File) ->true end}, + element(1,?current(M,F,A)), + {element(2, ?current(M,F,A)),element(3, ?current(M,F,A))}, + 1, true, + begin + case api_refac:is_exported( + {element(2, ?current(M,F,A)),element(3, ?current(M,F,A))}, + File) of + true -> + SearchPaths; + _ -> [File] + end + end])) + ]). + + + + + diff --git a/docs/doc/refac_batch_prefix_module.erl b/docs/doc/refac_batch_prefix_module.erl new file mode 100644 index 00000000..481df613 --- /dev/null +++ b/docs/doc/refac_batch_prefix_module.erl @@ -0,0 +1,41 @@ +%%@hidden +%%@private + +%%@doc This example code tries to add a prefix, which is provided by +%% the user, to every Erlang module name in the project. The scope of +%% the project is specified by a collection of directories. + +%%@author Huiqing Li +-module(refac_batch_prefix_module). + +-export([input_par_prompts/0, + select_focus/1, + composite_refac/1]). + +-behaviour(gen_composite_refac). + +-include("../../include/wrangler.hrl"). + +-spec input_par_prompts() -> [string()]. +input_par_prompts() -> + ["Prefix: "]. + +-spec select_focus(Args::#args{}) ->{ok, none}. +select_focus(_Args) -> + {ok, none}. + +-spec composite_refac(Args::#args{}) -> composite_refac(). +composite_refac(_Args=#args{user_inputs=[Prefix], + search_paths=SearchPaths}) -> + ?non_atomic( + ?refac_(rename_mod, + [{file, fun(File)-> + filename:extension(File)==".erl" end}, + {generator, fun(File) -> + Prefix++filename:basename(File) + end}, + false, + SearchPaths])). + + + diff --git a/docs/doc/refac_batch_rename_fun.erl b/docs/doc/refac_batch_rename_fun.erl new file mode 100644 index 00000000..e4f11315 --- /dev/null +++ b/docs/doc/refac_batch_rename_fun.erl @@ -0,0 +1,50 @@ +%%@author Huiqing Li + +%%@hidden +%%@private +-module(refac_batch_rename_fun). + +%%@hidden +%%@private +-export([composite_refac/1, select_focus/1, input_par_prompts/0]). + +-behaviour(gen_composite_refac). + +-include_lib("../include/wrangler.hrl"). + +input_par_prompts() -> + []. + +select_focus(_Args) -> + {ok, none}. + +composite_refac(_Args=#args{search_paths=SearchPaths}) -> + ?non_atomic(?refac_(rename_fun, + [{file, fun(_File)-> true end}, + fun({F, _A}) -> + camelCase_to_camel_case(F) /= F + end, + {generator, fun({_File, F,_A}) -> + camelCase_to_camel_case(F) + end}, + SearchPaths])). + + +%% transform camelCase atom to camel_case. +camelCase_to_camel_case(Name) -> + list_to_atom(camelCase_to_camel_case_1( + atom_to_list(Name),[])). + +camelCase_to_camel_case_1([], Acc) -> + lists:reverse(Acc); +camelCase_to_camel_case_1([H|T], Acc) + when (H >= 65) and (90 >= H)-> + case Acc of + [95|_] -> + camelCase_to_camel_case_1(T, [H+(97-65)|Acc]); + _ -> + camelCase_to_camel_case_1(T, [H+(97-65), 95|Acc]) + end; +camelCase_to_camel_case_1([H|T], Acc) -> + camelCase_to_camel_case_1(T, [H|Acc]). + diff --git a/docs/doc/refac_expr_to_behav_instance.erl b/docs/doc/refac_expr_to_behav_instance.erl new file mode 100644 index 00000000..b3727d12 --- /dev/null +++ b/docs/doc/refac_expr_to_behav_instance.erl @@ -0,0 +1,91 @@ +%%%------------------------------------------------------------------- +%%% @author Pablo Lamela Seijas +%%% @author Simon Thompson +%%% @copyright (C) 2015, Pablo Lamela, Simon Thompson +%%% @doc +%%% Parametrises an expression by moving it to another module as +%%% a behaviour callback. If the destination does not exist it is +%%% created. If the destination module is not a behaviour instance +%%% of this module, it is transformed into one. +%%% The new callback is added to the behaviour_info(callback) +%%% function, which is created if it does not exist. +%%% @end +%%% Created : 5 Jun 2015 by Pablo Lamela +%%%------------------------------------------------------------------- +-module(refac_expr_to_behav_instance). + +-behaviour(gen_composite_refac). + +-include("../../include/wrangler.hrl"). + +%%%=================================================================== +%% gen_composite_refac callbacks +-export([input_par_prompts/0,select_focus/1, + composite_refac/1]). + +%%%=================================================================== +%%% gen_composite_refac callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Prompts for parameter inputs +%% +%% @spec input_par_prompts() -> [string()] +%% @end +%%-------------------------------------------------------------------- +input_par_prompts() -> + ["Destination module : ", "Name for the new callback : "]. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Select the focus of the refactoring. +%% +%% @spec select_focus(Args::#args{}) -> +%% {ok, syntaxTree()} | +%% {ok, none} +%% @end +%%-------------------------------------------------------------------- +select_focus(#args{current_file_name=File, + highlight_range={Sta, End}, + tabwidth = TabWidth, + user_inputs = [_DestModule, CallbackName]} = _Args) -> + {ok, {AnnASTD, _InfoD}} = wrangler_ast_server:parse_annotate_file(File, true, [], TabWidth), + case wrangler_misc:funname_arities(AnnASTD, list_to_atom(CallbackName)) of + [] -> api_interface:pos_to_expr1(File,Sta,End); + _ -> {error, "There exists a function with the provided name in this module, please choose another name!"} + end. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% This function defines the composite refactoring script. +%% +%% @spec composite_refac(Args::#args{}) -> composite_refac()|[]. +%% @end +%%-------------------------------------------------------------------- +composite_refac(#args{current_file_name = FileName, + highlight_range = {Start, End}, + user_inputs = [DestModule, CallbackName], + search_paths = SearchPaths, + tabwidth = _TabWidth} = _Args) -> + TupleCallbackName = list_to_atom(CallbackName), + ?atomic([ + {refactoring, create_behav_instance, + [FileName, list_to_atom(DestModule), SearchPaths, composite_emacs]}, + {refactoring, fun_extraction, + [FileName, tuple_to_list(Start), tuple_to_list(End), + CallbackName, composite_emacs]}, + {refactoring, add_callbacks, + [FileName, CallbackName, SearchPaths, composite_emacs]}, + ?refac_(move_fun, + [FileName, + fun ({Name, _}) -> Name =:= TupleCallbackName; + (_Else) -> false + end, + list_to_atom(DestModule), + SearchPaths]) + ]). + diff --git a/docs/doc/refac_func_to_behav_instance.erl b/docs/doc/refac_func_to_behav_instance.erl new file mode 100644 index 00000000..2d8d00f0 --- /dev/null +++ b/docs/doc/refac_func_to_behav_instance.erl @@ -0,0 +1,84 @@ +%%%------------------------------------------------------------------- +%%% @author Pablo Lamela Seijas +%%% @author Simon Thompson +%%% @copyright (C) 2015, Pablo Lamela, Simon Thompson +%%% @doc +%%% Moves the function to another module as +%%% a behaviour callback. If the destination does not exist it is +%%% created. If the destination module is not a behaviour instance +%%% of this module, it is transformed into one. +%%% The new callback is added to the behaviour_info(callback) +%%% function, which is created if it does not exist. +%%% @end +%%% Created : 5 Jun 2015 by Pablo Lamela +%%%------------------------------------------------------------------- +-module(refac_func_to_behav_instance). + +-behaviour(gen_composite_refac). + +-include("../../include/wrangler.hrl"). + +%%%=================================================================== +%% gen_composite_refac callbacks +-export([input_par_prompts/0,select_focus/1, + composite_refac/1]). + +%%%=================================================================== +%%% gen_composite_refac callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Prompts for parameter inputs +%% +%% @spec input_par_prompts() -> [string()] +%% @end +%%-------------------------------------------------------------------- +input_par_prompts() -> + ["Destination module : "]. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Select the focus of the refactoring. +%% +%% @spec select_focus(Args::#args{}) -> +%% {ok, syntaxTree()} | +%% {ok, none} +%% @end +%%-------------------------------------------------------------------- +select_focus(#args{current_file_name=File, + cursor_pos=Pos, + tabwidth = _TabWidth, + user_inputs = [_DestModule]} = _Args) -> + api_interface:pos_to_fun_def(File, Pos). + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% This function defines the composite refactoring script. +%% +%% @spec composite_refac(Args::#args{}) -> composite_refac()|[]. +%% @end +%%-------------------------------------------------------------------- +composite_refac(#args{current_file_name = FileName, + focus_sel = FunDef, + user_inputs = [DestModule], + search_paths = SearchPaths, + tabwidth = _TabWidth} = _Args) -> + {_M, F, A} = api_refac:fun_define_info(FunDef), + ?atomic([ + {refactoring, create_behav_instance, + [FileName, list_to_atom(DestModule), SearchPaths, composite_emacs]}, + {refactoring, add_callback, + [FileName, atom_to_list(F), integer_to_list(A), SearchPaths, composite_emacs]}, + ?refac_(move_fun, + [FileName, + fun ({Name, Arity}) -> Name =:= F andalso Arity =:= A; + (_Else) -> false + end, + list_to_atom(DestModule), + SearchPaths]) + ]). + diff --git a/docs/doc/refac_keysearch_to_keyfind.erl b/docs/doc/refac_keysearch_to_keyfind.erl new file mode 100644 index 00000000..f2f07c11 --- /dev/null +++ b/docs/doc/refac_keysearch_to_keyfind.erl @@ -0,0 +1,74 @@ +%% @private +%% @hidden +-module(refac_keysearch_to_keyfind). + +-behaviour(gen_refac). + +-export([input_par_prompts/0, select_focus/1, + check_pre_cond/1, selective/0, + transform/1]). + +-include("../../include/wrangler.hrl"). + +%% No parameter input is required. +-spec (input_par_prompts/0::() -> [string()]). +input_par_prompts() -> []. + +%% No focus selection is required. +-spec (select_focus/1::(#args{}) -> {ok, syntaxTree()}|{ok, none}). +select_focus(_Args) ->{ok, none}. + +%% No precondition checking is required. +-spec (check_pre_cond/1::(#args{}) -> ok). +check_pre_cond(_Args) -> + ok. + +-spec (selective/0::()-> true). +selective() -> + true. + +%% Apply the transformation rules to all the Erlang files included in the +%% SearchPaths. +-spec (transform/1::(#args{}) -> {ok, [{filename(), filename(), syntaxTree()}]}). + +transform(_Args=#args{search_paths=SearchPaths})-> + ?STOP_TD_TP([rule_keysearch_to_keyfind()], SearchPaths). + +rule_keysearch_to_keyfind() -> + ?RULE(?T("case lists:keysearch(Key@, N@, TupleList@) of + Pats@@@ when Guards@@@ -> + Body@@@ + end"), + begin + NewPats@@@=make_new_pats(Pats@@@), + ?TO_AST("case lists:keyfind(Key@, N@, TupleList@) of + NewPats@@@ when Guards@@@ -> + Body@@@ + end") + end, + true). + +make_new_pats(ListOfPats) -> + [[make_new_pat(P)||P<-Pats]||Pats<-ListOfPats]. +make_new_pat(Pat) -> + case ?MATCH(?T("{value, T@}"), Pat) of + true -> + case api_refac:type(T@) of + variable -> + ?TO_AST("T@={_,_}"); + underscore-> + ?TO_AST("{_,_}"); + _ -> + T@ + end; + false -> + case ?MATCH(?T("false"), Pat) orelse + ?MATCH(?T("_"),Pat) of + true -> + Pat; + false -> + throw({error, "Transformation aborted."}) + end + end. + + diff --git a/docs/doc/refac_remove_an_argument.erl b/docs/doc/refac_remove_an_argument.erl new file mode 100644 index 00000000..561438f2 --- /dev/null +++ b/docs/doc/refac_remove_an_argument.erl @@ -0,0 +1,206 @@ +%% Copyright (c) 2013, Huiqing Li, Simon Thompson +%% All rights reserved. +%% +%% Redistribution and use in source and binary forms, with or without +%% modification, are permitted provided that the following conditions are met: +%% %% Redistributions of source code must retain the above copyright +%% notice, this list of conditions and the following disclaimer. +%% %% Redistributions in binary form must reproduce the above copyright +%% notice, this list of conditions and the following disclaimer in the +%% documentation and/or other materials provided with the distribution. +%% %% Neither the name of the copyright holders nor the +%% names of its contributors may be used to endorse or promote products +%% derived from this software without specific prior written permission. +%% +%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' +%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +%% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS +%% BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +%% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +%% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +%% OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +%% ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +%% @hidden +%% @private +-module(refac_remove_an_argument). + +-behaviour(gen_refac). + +-compile(export_all). + +%% Include files +-include("../../include/wrangler.hrl"). + +%%%=================================================================== +%% gen_refac callbacks +-export([input_par_prompts/0,select_focus/1, + check_pre_cond/1, selective/0, + transform/1]). + +%%%=================================================================== +%%% gen_refac callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Prompts for parameter inputs +%% +%% @spec input_par_prompts() -> [string()] +%% @end +%%-------------------------------------------------------------------- +input_par_prompts() -> + ["Parameter Index : "]. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Select the focus of the refactoring. +%% +%% @spec select_focus(Args::#args{}) -> +%% {ok, syntaxTree()} | +%% {ok, none} +%% @end +%%-------------------------------------------------------------------- +select_focus(_Args=#args{current_file_name=File, + cursor_pos=Pos}) -> + api_interface:pos_to_fun_def(File, Pos). + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Check the pre-conditions of the refactoring. +%% +%% @spec check_pre_cond(Args::#args{}) -> ok | {error, Reason} +%% @end +%%-------------------------------------------------------------------- +check_pre_cond(Args=#args{focus_sel=FunDef, + user_inputs=[I]}) -> + Ith=list_to_integer(I), + {_M,_F,A} = api_refac:fun_define_info(FunDef), + case Ith>=1 andalso Ith= + check_pre_cond_1(Args); + false -> + {error, "Index is invalid."} + end. + + +check_pre_cond_1(_Args=#args{focus_sel=FunDef, + user_inputs=[I]}) -> + Ith=list_to_integer(I), + IthArgs=?FULL_TD_TU([?COLLECT(?T("f@(Args@@)when Guard@@-> Bs@@;"), + lists:nth(Ith, Args@@), + true)], + FunDef), + case lists:all(fun(A) -> api_refac:type(A) == variable end, IthArgs) of + true -> + case lists:all(fun(A) -> length(api_refac:var_refs(A)) == 0 end, IthArgs) of + true -> + ok; + _ -> + {error, "Parameter is used."} + end; + _ -> + {error, "The parameter selectted is not a variable."} + end. + + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Selective transformation or not. +%% +%% @spec selective() -> boolean() +%% @end +%%-------------------------------------------------------------------- +selective() -> + false. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% This function does the actual transformation. +%% +%% @spec transform(Args::#args{}) -> +%% {ok, [{filename(), filename(), syntaxTree()}]} | +%% {error, Reason} +%% @end +%%-------------------------------------------------------------------- +transform(Args=#args{current_file_name=File,focus_sel=FunDef, + user_inputs=[I]}) -> + {M,F,A} = api_refac:fun_define_info(FunDef), + Ith = list_to_integer(I), + {ok, Res}=transform_in_cur_file(Args, {M,F,A}, Ith), + case api_refac:is_exported({F,A}, File) of + true -> + {ok, Res1}=transform_in_client_files(Args, {M,F,A}, Ith), + {ok, Res++Res1}; + false -> + {ok, Res} + end. + +transform_in_cur_file(_Args=#args{current_file_name=File}, MFA, I) -> + ?FULL_TD_TP([rule1(MFA,I), + rule2(MFA,I), + rule3(MFA), + rule4(MFA, I)], + [File]). + + +transform_in_client_files(_Args=#args{current_file_name=File, + search_paths=SearchPaths}, + MFA, I) -> + ?FULL_TD_TP([rule2(MFA,I), + rule3(MFA)], + api_refac:client_files(File, SearchPaths)). + + +rule1({M,F,A}, Ith) -> + ?RULE(?T("f@(Args@@) when Guard@@ -> Bs@@;"), + begin NewArgs@@=delete(Ith, Args@@), + ?TO_AST("f@(NewArgs@@) when Guard@@->Bs@@;") + end, + api_refac:fun_define_info(f@) == {M, F, A} + ). + +%% Transform the different kinds of function applications. +rule2({M,F,A}, Ith) -> + ?RULE(?FUN_APPLY(M,F,A), + begin + Args = api_refac:get_app_args(_This@), + NewArgs=delete(Ith, Args), + api_refac:update_app_args(_This@, NewArgs) + end, + true). + +rule3({M,F,A}) -> + ?RULE(?T("F@"), + api_refac:make_arity_qualifier(F, A - 1), + api_refac:type(F@) == arity_qualifier andalso + api_refac:fun_define_info(F@) == {M, F, A}). + +rule4({_M, F, A}, Ith) -> + ?RULE(?T("Spec@"), + api_spec:rm_arg_type_from_spec(_This@, Ith), + api_spec:is_type_spec(Spec@, {F, A})). + + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== + +delete(Ith, Args) when is_list(Args) -> + lists:sublist(Args, Ith-1)++ lists:nthtail(Ith, Args); +delete(Ith, Arg) -> + Str=lists:flatten( + io_lib:format( + "fun(ArgList) -> + lists:sublist(ArgList, ~p-1) ++ + lists:nthtail(~p, ArgList) + end(~s)", [Ith, Ith, ?PP(Arg)])), + ?TO_AST(Str). + diff --git a/docs/doc/refac_remove_an_import_attribute.erl b/docs/doc/refac_remove_an_import_attribute.erl new file mode 100644 index 00000000..77deff46 --- /dev/null +++ b/docs/doc/refac_remove_an_import_attribute.erl @@ -0,0 +1,92 @@ +%% Copyright (c) 2013, Huiqing Li, Simon Thompson +%% All rights reserved. +%% +%% Redistribution and use in source and binary forms, with or without +%% modification, are permitted provided that the following conditions are met: +%% %% Redistributions of source code must retain the above copyright +%% notice, this list of conditions and the following disclaimer. +%% %% Redistributions in binary form must reproduce the above copyright +%% notice, this list of conditions and the following disclaimer in the +%% documentation and/or other materials provided with the distribution. +%% %% Neither the name of the copyright holders nor the +%% names of its contributors may be used to endorse or promote products +%% derived from this software without specific prior written permission. +%% +%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' +%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +%% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS +%% BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +%% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +%% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +%% OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +%% ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +%%@doc This module shows how to write refactorings +%% use the Wrangler API. + +%% The refactoring implemented in this module removes +%% the import attributes importing a user specified +%% module, and qualify the calls to those functions +%% imported from that module. + +%% @hidden +%% @private +-module(refac_remove_an_import_attribute). + +-behaviour(gen_refac). + +%% export of callback function. +-export([input_par_prompts/0, select_focus/1, + check_pre_cond/1, selective/0, + transform/1]). + +-include("../../include/wrangler.hrl"). + +%% The user needs to input the module name. +-spec (input_par_prompts/0::() -> [string()]). +input_par_prompts() -> ["Module name:"]. + +%% No focus selection is needed. +-spec (select_focus/1::(#args{}) -> {ok, syntaxTree()}|{ok, none}). +select_focus(_Args) ->{ok, none}. + +%% Pre-condition checking. +-spec (check_pre_cond/1::(#args{}) -> ok|{error, term()}). +check_pre_cond(_Args=#args{current_file_name=File, + user_inputs=[ModuleName]}) -> + case is_imported(File, ModuleName) of + true -> + ok; + false -> + {error, "The module specified is not imported"} + end. + +selective()-> + false. + +%%Do the actual program transformation here. +-spec (transform/1::(#args{}) -> {ok, [{{filename(), filename()}, syntaxTree()}]}|{error, term()}). +transform(Args=#args{current_file_name=File})-> + ?FULL_TD_TP([rule1(Args), + rule2(Args)], [File]). + +%% qualify function calls. +rule1(_Args=#args{user_inputs=[ModuleName]}) -> + ?RULE(?T("F@(Args@@)"), + ?TO_AST(ModuleName++":F@(Args@@)"), + api_refac:type(F@) /= module_qualifier andalso + list_to_atom(ModuleName) == element(1,api_refac:fun_define_info(F@))). + + +%% remove import attributes related. +rule2(_Args=#args{user_inputs=[ModuleName]}) -> + ?RULE(?T("A@"), ?TO_AST(""), + api_refac:is_import(A@, list_to_atom(ModuleName))). + +%%utility functions. +is_imported(File, ModuleName) -> + api_refac:imported_funs(File, ModuleName) /= []. + diff --git a/docs/doc/refac_specialise_a_function.erl b/docs/doc/refac_specialise_a_function.erl new file mode 100644 index 00000000..fc1404bd --- /dev/null +++ b/docs/doc/refac_specialise_a_function.erl @@ -0,0 +1,272 @@ +%% Copyright (c) 2013, Huiqing Li, Simon Thompson +%% All rights reserved. +%% +%% Redistribution and use in source and binary forms, with or without +%% modification, are permitted provided that the following conditions are met: +%% %% Redistributions of source code must retain the above copyright +%% notice, this list of conditions and the following disclaimer. +%% %% Redistributions in binary form must reproduce the above copyright +%% notice, this list of conditions and the following disclaimer in the +%% documentation and/or other materials provided with the distribution. +%% %% Neither the name of the copyright holders nor the +%% names of its contributors may be used to endorse or promote products +%% derived from this software without specific prior written permission. +%% +%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' +%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +%% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS +%% BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +%% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +%% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +%% OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +%% ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +%% +%%@doc This module shows how to write refactorings +%% use the Wrangler API. + +%% This refactoring specialise a function over a particular +%% constant parameter of this function. +%% To apply this refactoring, highlight the actual parameter +%% a function application of the function under consideration, +%% then select 'Apply adhoc refactoring' from the menu, +%% and Wrangler will prompt you to input the refactoring +%% name, which is supposed to be the module name. +%% +%% @hidden +%% @private +-module(refac_specialise_a_function). + +-behaviour(gen_refac). + +-export([input_par_prompts/0, select_focus/1, + check_pre_cond/1, selective/0, + transform/1]). + +-include("../../include/wrangler.hrl"). + +%% The Emacs mini-buffer prompts for the user input parameters. +-spec (input_par_prompts/0::() -> [string()]). +input_par_prompts()-> + []. + +%% Select the focus of interest. If no selection is neeeded, +%% then return {ok, none}. When a proper actual parameter +%% has been selected, this function returns the {M,F,A} of +%% the function under consideration, the actual parameter +%% selected, and the index the parameter selected. +-spec (select_focus/1::(args()) -> {ok, {{atom(), atom(), integer()},syntaxTree(),integer()}}). +select_focus(#args{current_file_name=File, + highlight_range={Start, End}}) -> + {ok, Expr}=api_interface:range_to_node(File, {Start,End}, fun(E) ->is_expr(E) end), + {ok, App}= api_interface:pos_to_node( + File, Start, fun(Node)-> + is_the_enclosing_app(Node, Expr) + end), + ?MATCH(?T("Op@(As@@)"), App), + {M, F, A}=api_refac:fun_define_info(Op@), + {As1,_As2}=lists:splitwith(fun(E)->E/=Expr end, As@@), + Nth = length(As1)+1, + {ok, {{M,F,A},Expr,Nth}}. + +%% Pre-condition checking. +-spec (check_pre_cond/1::(#args{}) -> ok). +check_pre_cond(Args=#args{current_file_name=File, + focus_sel={{M,_F,_A},_Expr,_Nth}}) -> + case {ok, M} == api_refac:module_name(File) of + true -> + check_pre_cond_1(Args); + false -> + throw({error, "The function selected is not defined" + "in the current module."}) + end. + +check_pre_cond_1(Args=#args{focus_sel={_MFA, Expr, _Nth}}) -> + case api_refac:free_vars(Expr) of + [] -> + check_pre_cond_2(Args); + _ -> + throw({error, "The argument selected contains free variables."}) + end. + +check_pre_cond_2(#args{current_file_name=File, + focus_sel={MFA,_Expr, Nth}}) -> + FunDef= api_refac:mfa_to_fun_def(File, MFA), + NthPars = ?FULL_TD_TU([?COLLECT(?T("f@(Args@@)-> Bs@@;"), + lists:nth(Nth, Args@@), + true)], + FunDef), + case lists:all(fun(P)-> + wrangler_syntax:type(P) == variable + end, NthPars) of + true -> + ok; + false -> + throw({error, "Wrangler only supports specialisation over " + "a formal parameter that is a variable"}) + end. + +selective()-> + false. + +%% Do the actual program transformation here. +-spec (transform/1::(#args{}) -> {ok, [{{filename(), filename()}, syntaxTree()}]} + |{error, term()}). + +transform(Args=#args{current_file_name=File, + focus_sel={{_M,F,A},_Expr, _Nth}})-> + InscopeFuns = api_refac:inscope_funs(File), + M = list_to_atom(filename:basename(File, ".erl")), + NewFunName=case lists:member({M, F, A-1}, InscopeFuns) of + true -> + make_new_fun_name({M,F,A-1}, InscopeFuns); + false -> + atom_to_list(F) + end, + case api_refac:is_exported({F,A}, File) of + true -> + {ok, Res}=transform_in_client_files(Args, NewFunName), + case Res of + [] -> + %% no client files have been changed. + transform_in_cur_file(Args, NewFunName, false); + _ -> + %% some clients files have been changed. + {ok, Res1}=transform_in_cur_file(Args, NewFunName, true), + {ok, Res1++Res} + end; + false -> + %% function is not exported. + transform_in_cur_file(Args, NewFunName, false) + end. + +transform_in_cur_file(Args=#args{current_file_name=File}, NewFunName, true)-> + ?STOP_TD_TP([rule0(Args,NewFunName), + rule1(Args, NewFunName), + rule2(Args, NewFunName), + rule3(Args, NewFunName) + ], [File]); +transform_in_cur_file(Args=#args{current_file_name=File}, NewFunName, false) -> + ?STOP_TD_TP([rule0(Args, NewFunName), + rule1(Args, NewFunName), + rule2(Args,NewFunName)], [File]). + +transform_in_client_files(Args=#args{current_file_name=File, + search_paths=SearchPaths}, + NewFunName) -> + ?FULL_TD_TP([rule0(Args, NewFunName), + rule1(Args, NewFunName)], + api_refac:client_files(File, SearchPaths)). + +%% transformation rule: +%% remove the nth argument from a qualified application. +rule0(Args=#args{focus_sel={{M,F,A}, Expr, Nth}}, NewFunName) -> + ?RULE(?T("M@:F@(Args@@)"), + begin + NewArgs@@=delete(Nth,Args@@), + {ok,NewArgs1@@}=?FULL_TD_TP([rule0(Args, NewFunName), + rule1(Args, NewFunName)], NewArgs@@), + ?TO_AST("M@:"++NewFunName++"(NewArgs1@@)") + end, + api_refac:fun_define_info(F@) == {M,F,A} andalso + ?EQUAL(lists:nth(Nth, Args@@), Expr)). + +%% transformation rule: +%% remove the nth argument from an unqualified application. +rule1(Args=#args{focus_sel={{M,F,A}, Expr, Nth}}, NewFunName) -> + ?RULE(?T("F@(Args@@)"), + begin + NewArgs@@=delete(Nth,Args@@), + {ok,NewArgs1@@}=?FULL_TD_TP([rule0(Args, NewFunName), + rule1(Args, NewFunName)], NewArgs@@), + ?TO_AST(NewFunName++"(NewArgs1@@)") + end, + api_refac:fun_define_info(F@) == {M,F,A} andalso + ?EQUAL(lists:nth(Nth, Args@@), Expr)). + +%% transformation rule: +%% insert the new function right after the original one. +rule2(Args=#args{focus_sel={{M,F,A},_Expr,_Nth}}, NewFunName) -> + ?RULE(?T("F@"), + begin + NewFun=generate_specialised_fun(Args, F@, NewFunName), + {ok,NewF@}= ?FULL_TD_TP([rule0(Args, NewFunName), + rule1(Args, NewFunName)], F@), + [NewF@, NewFun] + end, + wrangler_syntax:type(F@) == function andalso + api_refac:fun_define_info(F@) == {M,F,A}). + +%% transformation rule: +%% add the new function to export list. +rule3(_Args=#args{focus_sel={{_M,F,A},_Expr,_Nth}}, NewFunName) -> + ?RULE(?T("F@"), + api_refac:add_to_export_after(F@, {NewFunName, A - 1}, {F,A}), + api_refac:is_attribute(F@, export)). + +generate_specialised_fun(Args, FunDef, NewFunName) -> + {ok,NewFunDef}=?FULL_TD_TP([rule4(Args, NewFunName)], FunDef), + NewFunDef. + +rule4(Args=#args{focus_sel={{_M,F,A}, _Expr, Nth}}, NewFunName) -> + ?RULE(?T("f@(Args@@) -> Bs@@;"), + begin NewArgs@@=delete(Nth, Args@@), + NthPar = lists:nth(Nth, Args@@), + NewBs@@=transform_in_body(Args,Bs@@,NthPar, NewFunName), + ?TO_AST(NewFunName++"(NewArgs@@)->NewBs@@;") + end, + length(Args@@) == A andalso wrangler_syntax:is_atom(F@, F)). + +transform_in_body(Args, Body, NthPar, NewFunName) -> + {ok, Body1}=?FULL_TD_TP([rule5(Args,NthPar,NewFunName), + rule6(Args, NthPar, NewFunName)], Body), + Body1. + +rule5(#args{focus_sel={{M,F,A}, Expr, Nth}},NthPar, NewFunName) -> + ?RULE(?T("F@(Args@@)"), + begin + NewArgs@@=delete(Nth, Args@@), + ?TO_AST(NewFunName++"(NewArgs@@)") + end, + api_refac:fun_define_info(F@) == {M,F,A} andalso + check_nth_arg(Args@@, Expr, Nth, NthPar)). + +%% replace the use of the formal parameter with the expression selected. +rule6(#args{focus_sel={_MFA,Expr,_Nth}}, NthPar, _NewFunName) -> + ?RULE(?T("V@"), + Expr, + wrangler_syntax:type(V@) == variable andalso + api_refac:variable_define_pos(V@) == + api_refac:variable_define_pos(NthPar)). + +%% some utility functions. + +check_nth_arg(ArgList, Expr, Nth, NthPar) -> + NthArg=lists:nth(Nth, ArgList), + ?EQUAL(NthArg, Expr) + orelse + (wrangler_syntax:type(NthArg) == variable andalso + api_refac:variable_define_pos(NthPar) == + api_refac:variable_define_pos(NthArg)). + +is_expr(Node) -> + api_refac:syntax_category(Node) == expression. + +is_the_enclosing_app(Node, Expr) -> + wrangler_syntax:type(Node) == application andalso + lists:member(Expr, wrangler_syntax:application_arguments(Node)). + +delete(N, List)-> + {L1,L2}=lists:split(N-1, List), + L1++tl(L2). + +make_new_fun_name({ModName,OldName, Arity},InscopeFuns) -> + NewName=list_to_atom(atom_to_list(OldName)++"_1"), + case lists:member({ModName, NewName,Arity}, InscopeFuns) of + true -> + make_new_fun_name({ModName,NewName, Arity}, InscopeFuns); + _ -> + atom_to_list(NewName) + end. diff --git a/docs/doc/refac_swap_function_arguments.erl b/docs/doc/refac_swap_function_arguments.erl new file mode 100644 index 00000000..20f493b8 --- /dev/null +++ b/docs/doc/refac_swap_function_arguments.erl @@ -0,0 +1,193 @@ +%% Copyright (c) 2013, Huiqing Li, Simon Thompson +%% All rights reserved. +%% +%% Redistribution and use in source and binary forms, with or without +%% modification, are permitted provided that the following conditions are met: +%% %% Redistributions of source code must retain the above copyright +%% notice, this list of conditions and the following disclaimer. +%% %% Redistributions in binary form must reproduce the above copyright +%% notice, this list of conditions and the following disclaimer in the +%% documentation and/or other materials provided with the distribution. +%% %% Neither the name of the copyright holders nor the +%% names of its contributors may be used to endorse or promote products +%% derived from this software without specific prior written permission. +%% +%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' +%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +%% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS +%% BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +%% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +%% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +%% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +%% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +%% OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +%% ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +%% +%%@doc This module shows how to write refactorings +%% use the Wrangler API. + +%% The refactoring implemented in this module +%% swaps the Ith and Jth arguments of a function +%% selected by the user. The value of Ith and Jth +%% are user input. +%% To perform this refactoring, point the cursor to +%% the function definition, and then select +%% 'Apply adhoc refactoring' from the menu, after +%% that, Wrangler will prompts you input the +%% the refactoring rename, which is supposed to be +%% the module name, and then you will prompted to +%% input the values of Ith and Jth. +%% @hidden +%% @private +-module(refac_swap_function_arguments). + +-behaviour(gen_refac). + +-export([input_par_prompts/0, select_focus/1, + check_pre_cond/1, selective/0, + transform/1]). + +-export([swap_args/7]). + +-include("../../include/wrangler.hrl"). + +-import(api_refac, [fun_define_info/1]). + +%% The user needs to input the indexes of +%% the parameters to swap. +input_par_prompts() -> + ["Parameter Index 1: ", + "Parameter Index 2: "]. + +%% The user needs to point the cursor to the +%% function definition whose parameters is to +%% be re-arranged. +%% Note: the function: pos_to_fun_def will be +%% moved to module refac_api. +select_focus(_Args=#args{current_file_name=File, + cursor_pos=Pos}) -> + api_interface:pos_to_fun_def(File, Pos). + +%% Check that the values of Ith and Jth inputted +%% by the user are valid. +check_pre_cond(_Args=#args{focus_sel=FunDef, + user_inputs=[I, J]}) -> + Ith=list_to_integer(I), + Jth=list_to_integer(J), + {_M,_F,A} = fun_define_info(FunDef), + case Ith /=Jth of + true -> + case Ith>=1 andalso Ith= + case Jth>=1 andalso Jth= + ok; + false -> + {error, "Index 2 is invalid."} + end; + false -> + {error, "Index 1 is invalid."} + end; + false -> + {error, "Index 1 and Index 2 are the same."} + end. + +selective() -> + false. +%% Do the program transformation here. +transform(Args=#args{current_file_name=File,focus_sel=FunDef, + user_inputs=[I, J]}) -> + {M,F,A} = fun_define_info(FunDef), + I1 = list_to_integer(I), + J1 = list_to_integer(J), + {ok, Res}=transform_in_cur_file(Args, {M,F,A}, I1, J1), + case api_refac:is_exported({F,A}, File) of + true -> + {ok, Res1}=transform_in_client_files(Args, {M,F,A}, I1, J1), + {ok, Res++Res1}; + false -> + {ok, Res} + end. + +%% transform the current file. +transform_in_cur_file(_Args=#args{current_file_name=File},MFA, I, J)-> + ?FULL_TD_TP([rule1(MFA, I, J), + rule2(MFA, I, J), + rule3(MFA, I, J)], + [File]). + +%% transform the client files. +transform_in_client_files(_Args=#args{current_file_name=File, + search_paths=SearchPaths}, + MFA, I, J) -> + ?FULL_TD_TP([rule2(MFA, I, J)], + api_refac:client_files(File, SearchPaths)). + + +%% transform the function definition itself. +rule1({M,F,A}, I, J) -> + ?RULE(?T("f@(Args@@) when Guard@@ -> Bs@@;"), + begin + NewArgs@@=swap(Args@@,I,J), + ?TO_AST("f@(NewArgs@@) when Guard@@->Bs@@;") + end, + api_refac:fun_define_info(_This@) == {M, F, A} + ). + +%% Transform the different kinds of function applications. +rule2({M,F,A}, I, J) -> + ?RULE(?FUN_APPLY(M,F,A), + begin + Args=api_refac:get_app_args(_This@), + NewArgs=swap(Args, I, J), + api_refac:update_app_args(_This@,NewArgs) + end, + true). + +rule3({_M, F, A}, I, J) -> + ?RULE(?T("Spec@"), + api_spec:swap_arg_types_in_spec(_This@, I, J), + api_spec:is_type_spec(Spec@, {F, A})). + +%% utility functions. +swap(List, I, J) when is_list(List) -> + Ith = lists:nth(I, List), + Jth = lists:nth(J, List), + T = list_to_tuple(List), + T1=setelement(J, setelement(I, T, Jth), Ith), + tuple_to_list(T1); +swap(Node, I, J) -> + Str=lists:flatten( + io_lib:format( + "fun(List) -> + Ith = lists:nth(~p, List), + Jth = lists:nth(~p, List), + T = list_to_tuple(List), + T1=setelement(~p, setelement(~p, T, Jth), Ith), + tuple_to_list(T1) + end(~s)", [I, J, J, I, ?PP(Node)])), + ?TO_AST(Str). + + +swap_args(FileName, {FunName, Arity}, Index1, Index2, SearchPaths, Editor, TabWidth) -> + {ok, {AnnAST, _Info}} = wrangler_ast_server:parse_annotate_file(FileName, true, SearchPaths, TabWidth), + ModName=list_to_atom(filename:basename(FileName, ".erl")), + case wrangler_misc:funname_to_defpos(AnnAST, {ModName, FunName, Arity}) of + {ok, DefPos} -> + {ok, FunDef} = api_interface:pos_to_fun_def(FileName, DefPos), + Args=#args{current_file_name=FileName, + focus_sel=FunDef, + user_inputs=[Index1, Index2], + search_paths=SearchPaths, + tabwidth=TabWidth}, + case check_pre_cond(Args) of + ok -> + {ok, Res}=transform(Args), + wrangler_write_file:write_refactored_files(Res,Editor,TabWidth,""); + {error, Reason} -> + {error, Reason} + end; + {error, Reason} -> + {error, Reason} + end. diff --git a/docs/doc/refac_unfold_behav_instance.erl b/docs/doc/refac_unfold_behav_instance.erl new file mode 100644 index 00000000..7af93c89 --- /dev/null +++ b/docs/doc/refac_unfold_behav_instance.erl @@ -0,0 +1,118 @@ +%%%------------------------------------------------------------------- +%%% @author Pablo Lamela Seijas +%%% @author Simon Thompson +%%% @copyright (C) 2015, Pablo Lamela, Simon Thompson +%%% @doc +%%% Unfold an instance of a behaviour into its behaviour definition. +%%% In order to prevent other instances from working, the refactoring +%%% makes a copy of the behaviour definition previous to the unfolding. +%%% Optionally, the dynamic calls from the behaviour definition to +%%% the behaviour instance can be instanciated, but this process may +%%% instanciate the wrong calls if they have the same name than +%%% any of the behaviour callbacks. +%%% @end +%%% Created : 16 Jun 2015 by Pablo Lamela +%%%------------------------------------------------------------------- +-module(refac_unfold_behav_instance). + +-behaviour(gen_composite_refac). + +-include("../../include/wrangler.hrl"). + +%%%=================================================================== +%% gen_composite_refac callbacks +-export([input_par_prompts/0,select_focus/1, + composite_refac/1]). + +%%%=================================================================== +%%% gen_composite_refac callbacks +%%%=================================================================== + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Prompts for parameter inputs +%% +%% @spec input_par_prompts() -> [string()] +%% @end +%%-------------------------------------------------------------------- +input_par_prompts() -> + ["Name for the output module : "]. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Select the focus of the refactoring. +%% +%% @spec select_focus(Args::#args{}) -> +%% {ok, syntaxTree()} | +%% {ok, none} +%% @end +%%-------------------------------------------------------------------- +select_focus(_Args) -> + {ok, none}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% This function defines the composite refactoring script. +%% +%% @spec composite_refac(Args::#args{}) -> composite_refac()|[]. +%% @end +%%-------------------------------------------------------------------- +composite_refac(#args{current_file_name = FileName, + user_inputs = [NewModuleNameStr], + search_paths = SearchPaths, + tabwidth = _TabWidth} = _Args) -> + DefModuleStr = ?PP(hd(find_behaviour_module(FileName))), + DefModule = list_to_atom(DefModuleStr), + NewModule = list_to_atom(NewModuleNameStr), + NewFileName = filename:dirname(FileName) ++ "/" ++ NewModuleNameStr ++ ".erl", + %[DefModuleFile] = wrangler_gen:gen_file_names(DefModule, SearchPaths), + %% [ASTFuncs|_] = collect_callbacks(DefModuleFile), + %% Funcs = hd(lists:map(fun wrangler_syntax:concrete/1, ASTFuncs)), + ?atomic([?refac_(copy_mod, + [DefModule, + NewModule, + [FileName], + true, + SearchPaths]), + ?interactive(atomic, + [?refac_(instantiate_calls, + [NewFileName, + {generator, fun (_) -> filename:basename(FileName, ".erl") end}, + true, SearchPaths])]), + ?refac_(move_fun, + [FileName, + fun (_FA) -> true end, + NewModule, + true, + SearchPaths + ]), + {refactoring, remove_behav_dec, [NewFileName, SearchPaths, composite_emacs]} + %% , ?interactive( + %% [?refac_(unfold_fun_app, + %% [NewModule, + %% fun (FA) -> not lists:member(FA, Funcs) end, + %% fun ({D, F, A}) -> D =:= NewModule andalso + %% lists:member({F, A}, Funcs) end, + %% true, + %% SearchPaths + %% ])]) + ]). + +%% collect_callbacks(File) -> +%% ?FULL_TD_TU([?COLLECT(?T("behaviour_info(callbacks) -> Funcs@@;"), +%% Funcs@@, true)], +%% [File]). + +find_behaviour_module(File) -> + ?FULL_TD_TU([?COLLECT(?T("-behaviour(module@)."), + module@, true), + ?COLLECT(?T("-behavior(module@)."), + module@, true)], + [File]). + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/docs/doc/regexp_re.erl b/docs/doc/regexp_re.erl new file mode 100644 index 00000000..3b4a8a4b --- /dev/null +++ b/docs/doc/regexp_re.erl @@ -0,0 +1,104 @@ +%% @private +%% @hidden +-module(regexp_re). + +-export([old_api_module_name/0]). + +-export([match/2, + first_match/2, + matches/2, + sub/3, + gsub/3, + split/2, + parse/1 + ]). + +old_api_module_name() -> + regexp. + +match(String, RegExp) -> + try re:run(String, RegExp, [global]) of + {match, Match} -> + {Start0, Len} = lists:last( + lists:ukeysort( + 2, lists:append(Match))), + Start = Start0+1, + {match, Start, Len}; + nomatch -> nomatch + catch + error:_-> + {error, Error}=re:compile(RegExp), + {error, Error} + end. + +first_match(String, RegExp) -> + try re:run(String, RegExp) of + {match, [{Start0, Len}]} -> + Start = Start0 +1, + {match, Start, Len}; + nomatch -> nomatch + catch + error:_-> + re:compile(RegExp) + end. + +matches(String, RegExp) -> + try re:run(String, RegExp, [global]) of + {match, Res} -> + Matches=[{Start+1, Len}|| + {Start, Len}<-lists:append(Res)], + {match, Matches}; + nomatch -> + {match, []} + catch + error:_-> + re:compile(RegExp) + end. + + +sub(String, RegExp, New) -> + try re:replace(String, RegExp, New, [{return, list}]) of + NewString -> + Count = case re:run(String,RegExp) of + nomatch -> 0; + _ -> 1 + end, + {ok, NewString, Count} + catch + error:_ -> + re:compile(RegExp) + end. + + +gsub(String, RegExp, New) -> + try re:replace(String, RegExp, New, [{return, list}]) of + NewString -> + Count = case re:run(String,RegExp, [global]) of + nomatch -> 0; + {match, Matches}-> + length(lists:append(Matches)) + end, + {ok, NewString, Count} + catch + error:_ -> + re:compile(RegExp) + end. + + +split(String, RegExp) -> + try re:split(String, RegExp, [{return, list}]) of + SplitList -> + {ok, SplitList} + catch + error:_ -> + re:compile(RegExp) + end. + +parse(RegExp) -> + re:compile(RegExp). + + +%% inspect() -> +%% ["regexp:split(String, "")", +%% "regexp:split(String, " ")"]. + diff --git a/docs/doc/stylesheet.css b/docs/doc/stylesheet.css new file mode 100644 index 00000000..ab170c09 --- /dev/null +++ b/docs/doc/stylesheet.css @@ -0,0 +1,55 @@ +/* standard EDoc style sheet */ +body { + font-family: Verdana, Arial, Helvetica, sans-serif; + margin-left: .25in; + margin-right: .2in; + margin-top: 0.2in; + margin-bottom: 0.2in; + color: #000000; + background-color: #ffffff; +} +h1,h2 { + margin-left: -0.2in; +} +div.navbar { + background-color: #add8e6; + padding: 0.2em; +} +h2.indextitle { + padding: 0.4em; + background-color: #add8e6; +} +h3.function,h3.typedecl { + background-color: #add8e6; + padding-left: 1em; +} +div.spec { + margin-left: 2em; + background-color: #eeeeee; +} +a.module { + text-decoration:none +} +a.module:hover { + background-color: #eeeeee; +} +ul.definitions { + list-style-type: none; +} +ul.index { + list-style-type: none; + background-color: #eeeeee; +} + +/* + * Minor style tweaks + */ +ul { + list-style-type: square; +} +table { + border-collapse: collapse; +} +td { + padding: 3 +} diff --git a/docs/doc/symbolic_evaluation/core/core_arit_calc.html b/docs/doc/symbolic_evaluation/core/core_arit_calc.html new file mode 100644 index 00000000..c14e174d --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/core_arit_calc.html @@ -0,0 +1,59 @@ + + + + +Module core_arit_calc + + + + +
    + +

    Module core_arit_calc

    + +Arithmetic Calculations Core - Simplification of arithmetic operations involving integer literals or arbitrary expressions. +

    Copyright © (C) 2013, Gabriela Cunha Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +

    Description

    +Arithmetic Calculations Core - Simplification of arithmetic operations involving integer literals or arbitrary expressions.

    + + The four basic arithmetic operators plus the operator rem are covered for integers, while only + and - are simplified for arbitrary expressions. + Some examples of simplifications are given below: +
      +
    • + (1 + 2 * 3 - 2) div 1 becomes 5. +
    • +
    • + foo(X) + 2 * foo(X) is simplified to 3 * foo(X). +
    • +
    + +

    Function Index

    + +
    rules/2 + Returns the list of arithmetics calculations rules.
    + +

    Function Details

    + +

    rules/2

    +
    +

    rules(X1::term(), X2::term()) -> [rule()]

    +

    + Returns the list of arithmetics calculations rules. The rules are organised in the following order: +

      +
    • Integer sum
    • +
    • Integer subtraction
    • +
    • Integer multiplication
    • +
    • Integer division
    • +
    • Integer rem
    • +
    • Arbitrary expressions sum
    • +
    • Arbitrary expressions subtraction
    • +

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/core_arit_simpl.html b/docs/doc/symbolic_evaluation/core/core_arit_simpl.html new file mode 100644 index 00000000..b3805c7f --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/core_arit_simpl.html @@ -0,0 +1,56 @@ + + + + +Module core_arit_simpl + + + + +
    + +

    Module core_arit_simpl

    + + Arithmetic Simplifications Core - Basic straightforward arithmetic simplifications. +

    Copyright © (C) 2013, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +

    Description

    + Arithmetic Simplifications Core - Basic straightforward arithmetic simplifications. The following simplifications are covered: +
      +
    • Sum by zero - Expressions of type Exp + 0 and 0 + Exp are transformed into Exp. For example, X + 0 is modified to X.
    • +
    • Subtraction by zero - Subtractions with zero as the second operand are modified. For instance, Y - 0 becomes Y.
    • +
    • Subtraction from zero - Expressions that match 0 - Exp are altered to -Exp. To exemplify, 0 - Y is changed to -Y.
    • +
    • Multiplication by one - Expressions of the formats Exp * 1 and 1 * Exp are simplified to Exp. To illustrate, Z * 1 is modified to Z.
    • +
    • Multiplication by zero - Multiplications containing zero as an operand are simplified to zero.
    • +
    • Division by one - Divisions by one, using the operator (div), are replaced by the numerator. For example, 3 div 1 is transformed to 3.
    • +
    + + These simplifications can by applied to any valid Erlang expression. +

    Function Index

    + +
    rules/2 + Returns the list of arithmetic simplification rules.
    + +

    Function Details

    + +

    rules/2

    +
    +

    rules(X1::term(), X2::term()) -> [rule()]

    +

    + Returns the list of arithmetic simplification rules. This list includes, in order, rules for the following possibilities: +

      +
    • Sub by zero
    • +
    • Sub from zero
    • +
    • Sum by zero
    • +
    • Multiplication by one rule
    • +
    • Multiplication by zero
    • +
    • Division by one
    • +

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/core_arithmetics.html b/docs/doc/symbolic_evaluation/core/core_arithmetics.html new file mode 100644 index 00000000..4bb66e99 --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/core_arithmetics.html @@ -0,0 +1,40 @@ + + + + +Module core_arithmetics + + + + +
    + +

    Module core_arithmetics

    + +Arithmetic Operators Core - Covers arithmetic expressions. +

    Copyright © (C) 2014, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +

    Description

    +Arithmetic Operators Core - Covers arithmetic expressions.

    + + The simplifications performed are divided into two minor cores: Arithmetic Simplifications Core and Arithmetic Calculations Core. +

    Function Index

    + +
    rules/2 + Returns the list of arithmetics rules.
    + +

    Function Details

    + +

    rules/2

    +
    +

    rules(A::term(), B::term()) -> [rule()]

    +

    + Returns the list of arithmetics rules. The returned list of rules, contains the rules from Arithmetic Simplifications Core first and then the rules of Arithmetic Calculations Core.

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/core_boolean_operators.html b/docs/doc/symbolic_evaluation/core/core_boolean_operators.html new file mode 100644 index 00000000..d1f5d358 --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/core_boolean_operators.html @@ -0,0 +1,91 @@ + + + + +Module core_boolean_operators + + + + +
    + +

    Module core_boolean_operators

    + + Boolean Operators Core - Simplifies the defined boolean operators to true or false. +

    Copyright © (C) 2014, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +

    Description

    + Boolean Operators Core - Simplifies the defined boolean operators to true or false. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation -> Boolean Operators. +

    + The following list of boolean operators that receives parameters of any type was implemented: + + >, + <, + >=, + =<, + /=, + =/=, + ==, + =:=, + is_atom/1, is_boolean/1, is_integer/1, is_float/1, is_function/1, is_function/2, is_list/1, is_number/1, is_tuple/1. + +

    +

    + Furthermore, the following list of operators that only simplify boolean expressions was created: and, andalso, or, orelse, xor, not/1. +

    + Examples of usage: +
      +
    • + 2 > 1 is simplified to true. +
    • +
    • + is_list({1,2,3}) is simplified to false. +
    • +
    • + true andalso false is simplified to false. +
    • +
    +

    Function Index

    + +
    rules/2 + Returns the list of boolean operators rules.
    + +

    Function Details

    + +

    rules/2

    +
    +

    rules(X1::term(), X2::term()) -> [rule()]

    +

    + Returns the list of boolean operators rules. The returned list of rules has the following order: +

      +
    • greater than
    • +
    • greater than or equal to
    • +
    • less than
    • +
    • less than or equal to
    • +
    • equal to
    • +
    • not equal to
    • +
    • exactly equal to
    • +
    • exactly not equal to
    • +
    • and
    • +
    • andalso
    • +
    • or
    • +
    • orelse
    • +
    • xor
    • +
    • not
    • +
    • is_list
    • +
    • is_integer
    • +
    • is_float
    • +
    • is_number
    • +
    • is_boolean
    • +
    • is_atom
    • +
    • is_tuple
    • +
    • is_function
    • +

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/core_case.html b/docs/doc/symbolic_evaluation/core/core_case.html new file mode 100644 index 00000000..289ec5e1 --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/core_case.html @@ -0,0 +1,78 @@ + + + + +Module core_case + + + + +
    + +

    Module core_case

    + +Case Core - Where possible, simplifies case expressions by the result of their evaluation. +

    Copyright © (C) 2014, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +

    Description

    +Case Core - Where possible, simplifies case expressions by the result of their evaluation.

    + + Examples of usage: +
      +
    • + + case [1,2] of
      +
      + [H | T] -> ok;
      + _ -> error
      +
      + end.
      +
      + is simplified to ok. +
    • +
    • + + begin
      +
      + X = true,
      + case X of
      +
      + true -> first;
      + _ -> second
      +
      + end
      +
      + end.
      +
      + becomes
      + + begin
      +
      + X = true,
      + first
      +
      + end.
      +
      +
    • +
    + +

    Function Index

    + +
    rules/2 + Returns a list with a single rule for the case simplification.
    + +

    Function Details

    + +

    rules/2

    +
    +

    rules(X1::{term(), VarsInfo::[{[{atom(), pos()}], syntaxTree()}], term()}, X2::term()) -> [rule()]

    +

    + Returns a list with a single rule for the case simplification.

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/core_funApp.html b/docs/doc/symbolic_evaluation/core/core_funApp.html new file mode 100644 index 00000000..defcf854 --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/core_funApp.html @@ -0,0 +1,88 @@ + + + + +Module core_funApp + + + + +
    + +

    Module core_funApp

    +Unfold Function Application Core - Substitute function calls by its application. +

    Copyright © (C) 2013, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +

    Description

    Unfold Function Application Core - Substitute function calls by its application.

    + + There are three types of transformations in this module: +
      +
    • Length - Replaces function calls to the function length/1 from the standard by the length of the list passed as parameter. For instance, length([10,20,30]) is transformed to 3.
    • +
    • + External calls - Function application for function calls from external modules. For example, consider the following module def:

      + + module(def).
      + export([sumList/1]).
      +
      + sumList([]) -> 0;
      + sumList([H | T]) when is_number(H) -> H + sumList(T).

      +
      + A call to def:sumList([1,2,3]) can be simplified to 1 + (2 + (3 + 0)). +
    • +
    • + Parametrized Anonymous Calls - This transformation is responsible for modifications in parametrized function calls of anonymous functions. For example: + fun(X) -> 2 * X end(1) is simplified to 2 * 1. +
    • +
    +

    Function Index

    + + + + + +
    anonymousCall_rule/0 + Rule that substitutes parametrized anonymous calls.
    collect/1 + Collects info from the exported functions in the file.
    functionCall_cond/6 + Boolean condition to execute the function application transformations.
    functionCall_rule/4 + Rule that substitutes external function calls.
    length_rule/0 + Rule that substitutes call to length/1 from the standard.
    + +

    Function Details

    + +

    anonymousCall_rule/0

    +
    +

    anonymousCall_rule() -> rule()

    +

    + Rule that substitutes parametrized anonymous calls.

    + +

    collect/1

    +
    +

    collect(File::filename()) -> [{mfa(), syntaxTree(), [syntaxTree()], syntaxTree()}]

    +

    + Collects info from the exported functions in the file.

    + +

    functionCall_cond/6

    +
    +

    functionCall_cond(FunInfo::mfa() | unknown, FunDefInfo::mfa() | unknown, InfoList::[{mfa(), syntaxTree(), [syntaxTree()], syntaxTree()}] | [{list, [{modulename(), [{mfa(), syntaxTree(), [syntaxTree()], syntaxTree()}]}]}], Args::syntaxTree(), BoundVars::[{atom(), pos()}], BoundVarsThis::[{atom(), pos()}]) -> boolean()

    +

    + Boolean condition to execute the function application transformations.

    + +

    functionCall_rule/4

    +
    +

    functionCall_rule(InfoList::[{mfa(), syntaxTree(), [syntaxTree()], syntaxTree()}] | [{list, [{modulename(), [{mfa(), syntaxTree(), [syntaxTree()], syntaxTree()}]}]}], FunDefInfo::mfa() | unknown, IsRefactoring::boolean(), BoundVars::[{atom(), pos()}]) -> rule()

    +

    + Rule that substitutes external function calls.

    + +

    length_rule/0

    +
    +

    length_rule() -> rule()

    +

    + Rule that substitutes call to length/1 from the standard.

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/core_if.html b/docs/doc/symbolic_evaluation/core/core_if.html new file mode 100644 index 00000000..98edc6f4 --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/core_if.html @@ -0,0 +1,78 @@ + + + + +Module core_if + + + + +
    + +

    Module core_if

    + +If Core - Where possible, simplifies if expressions by the result of their evaluation. +

    Copyright © (C) 2014, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +

    Description

    +If Core - Where possible, simplifies if expressions by the result of their evaluation.

    + + Examples of usage: +
      +
    • + + if
      +
      + false -> [2];
      + true -> []
      +
      + end.
      +
      + is simplified to []. +
    • +
    • + + begin
      +
      + X = true,
      + if
      +
      + X -> [2];
      + true -> []
      +
      + end
      +
      + end.
      +
      + becomes
      + + begin
      +
      + X = true,
      + [2]
      +
      + end.
      +
      +
    • +
    + +

    Function Index

    + +
    rules/2 + Returns a list with a single rule for the if simplification.
    + +

    Function Details

    + +

    rules/2

    +
    +

    rules(X1::{term(), VarsInfo::[{[{atom(), pos()}], syntaxTree()}], term()}, X2::term()) -> [rule()]

    +

    + Returns a list with a single rule for the if simplification.

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/core_lists_concat.html b/docs/doc/symbolic_evaluation/core/core_lists_concat.html new file mode 100644 index 00000000..0cf1082e --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/core_lists_concat.html @@ -0,0 +1,46 @@ + + + + +Module core_lists_concat + + + + +
    + +

    Module core_lists_concat

    + + Lists Concatenation Core - Simplifies lists concatenations. +

    Copyright © (C) 2014, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +

    Description

    + Lists Concatenation Core - Simplifies lists concatenations. Examples: +
      +
    • + "abc" ++ "def" is transformed to "abcdef". +
    • +
    • + [1,2,3] ++ [4,5,6] becomes [1,2,3,4,5,6]. +
    • +
    +

    Function Index

    + +
    rules/2 + Returns a list with a single rule for the lists concatenation simplification.
    + +

    Function Details

    + +

    rules/2

    +
    +

    rules(X1::term(), X2::term()) -> [rule()]

    +

    + Returns a list with a single rule for the lists concatenation simplification.

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/core_unreferenced_assign.html b/docs/doc/symbolic_evaluation/core/core_unreferenced_assign.html new file mode 100644 index 00000000..b8cc5ef5 --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/core_unreferenced_assign.html @@ -0,0 +1,105 @@ + + + + +Module core_unreferenced_assign + + + + +
    + +

    Module core_unreferenced_assign

    + +Remove Unreferenced Assignments - Removes assignments when the variables are not used afterwards. +

    Copyright © (C) 2014, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +

    Description

    +Remove Unreferenced Assignments - Removes assignments when the variables are not used afterwards.

    + + For example, the expression:
    + + begin
    +
    + A = 10,
    + B = 20,
    + C = 30,
    + E = A + B + C,
    + A
    +
    + end.
    +
    + can be simplified by these transformations to:
    + + begin
    +
    + A = 10,
    + A
    +
    + end.
    +
    +

    Function Index

    + + + + + + +
    collector_var_expr_value/1 + Collects all the assignments within Scope.
    collector_variable_occurrences/1 + Collects all the variable occurrences within Scope.
    rules/2 + List of rules to remove unreferenced assignments.
    variable_assignment_cond/2 + Returns true if the variable is unused and false otherwise.
    variable_assignment_rule/1 + Removes unreferenced assignments in a list of steps.
    variable_assignment_rule_begin/1 + Removes unreferenced assignments in a list of steps within a begin/end block.
    + +

    Function Details

    + +

    collector_var_expr_value/1

    +
    +

    collector_var_expr_value(Scope::syntaxTree()) -> [{[{atom(), pos()}], syntaxTree()}]

    +

    + Collects all the assignments within Scope.

    + +

    collector_variable_occurrences/1

    +
    +

    collector_variable_occurrences(Scope::syntaxTree()) -> [{atom(), pos()}]

    +

    + Collects all the variable occurrences within Scope.

    + +

    rules/2

    +
    +

    rules(X1::term(), Info::[{atom(), pos()}]) -> [rule()]

    +

    + List of rules to remove unreferenced assignments. This list contains the following rules: +

    + +

    variable_assignment_cond/2

    +
    +

    variable_assignment_cond(Var@::syntaxTree(), Info::[{atom(), pos()}]) -> boolean()

    +

    + Returns true if the variable is unused and false otherwise.

    + +

    variable_assignment_rule/1

    +
    +

    variable_assignment_rule(Info::[{atom(), pos()}]) -> rule()

    +

    + Removes unreferenced assignments in a list of steps.

    + +

    variable_assignment_rule_begin/1

    +
    +

    variable_assignment_rule_begin(Info::[{atom(), pos()}]) -> rule()

    +

    + Removes unreferenced assignments in a list of steps within a begin/end block.

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/erlang.png b/docs/doc/symbolic_evaluation/core/erlang.png new file mode 100644 index 00000000..987a618e Binary files /dev/null and b/docs/doc/symbolic_evaluation/core/erlang.png differ diff --git a/docs/doc/symbolic_evaluation/core/index.html b/docs/doc/symbolic_evaluation/core/index.html new file mode 100644 index 00000000..26e9203f --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/index.html @@ -0,0 +1,18 @@ + + + +The core application + + + + + + + +<h2>This page uses frames</h2> +<p>Your browser does not accept frames. +<br>You should go to the <a href="overview-summary.html">non-frame version</a> instead. +</p> + + + diff --git a/docs/doc/symbolic_evaluation/core/modules-frame.html b/docs/doc/symbolic_evaluation/core/modules-frame.html new file mode 100644 index 00000000..38213ee3 --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/modules-frame.html @@ -0,0 +1,20 @@ + + + +The core application + + + +

    Modules

    + + + + + + + + + +
    core_arit_calc
    core_arit_simpl
    core_arithmetics
    core_boolean_operators
    core_case
    core_funApp
    core_if
    core_lists_concat
    core_unreferenced_assign
    + + \ No newline at end of file diff --git a/docs/doc/symbolic_evaluation/core/overview-summary.html b/docs/doc/symbolic_evaluation/core/overview-summary.html new file mode 100644 index 00000000..81761c7f --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/overview-summary.html @@ -0,0 +1,37 @@ + + + + +Symbolic Evaluation Core + + + + +

    Symbolic Evaluation Core

    +

    Copyright © (C) 2014, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    +

    Authors: Gabriela Cunha Sampaio, Roberto Souto Maior de Barros Filho.

    + +The core files, use Wrangler, to propose a number of simplifications that perform symbolic evaluation in Erlang. More specifically, the following modules belong to these group: + + + + + + + +
    + +

    Generated by EDoc, Nov 5 2015, 16:30:15.

    + + diff --git a/docs/doc/symbolic_evaluation/core/stylesheet.css b/docs/doc/symbolic_evaluation/core/stylesheet.css new file mode 100644 index 00000000..ab170c09 --- /dev/null +++ b/docs/doc/symbolic_evaluation/core/stylesheet.css @@ -0,0 +1,55 @@ +/* standard EDoc style sheet */ +body { + font-family: Verdana, Arial, Helvetica, sans-serif; + margin-left: .25in; + margin-right: .2in; + margin-top: 0.2in; + margin-bottom: 0.2in; + color: #000000; + background-color: #ffffff; +} +h1,h2 { + margin-left: -0.2in; +} +div.navbar { + background-color: #add8e6; + padding: 0.2em; +} +h2.indextitle { + padding: 0.4em; + background-color: #add8e6; +} +h3.function,h3.typedecl { + background-color: #add8e6; + padding-left: 1em; +} +div.spec { + margin-left: 2em; + background-color: #eeeeee; +} +a.module { + text-decoration:none +} +a.module:hover { + background-color: #eeeeee; +} +ul.definitions { + list-style-type: none; +} +ul.index { + list-style-type: none; + background-color: #eeeeee; +} + +/* + * Minor style tweaks + */ +ul { + list-style-type: square; +} +table { + border-collapse: collapse; +} +td { + padding: 3 +} diff --git a/docs/doc/symbolic_evaluation/evaluator/erlang.png b/docs/doc/symbolic_evaluation/evaluator/erlang.png new file mode 100644 index 00000000..987a618e Binary files /dev/null and b/docs/doc/symbolic_evaluation/evaluator/erlang.png differ diff --git a/docs/doc/symbolic_evaluation/evaluator/eval_inline_variable.html b/docs/doc/symbolic_evaluation/evaluator/eval_inline_variable.html new file mode 100644 index 00000000..7b574ffa --- /dev/null +++ b/docs/doc/symbolic_evaluation/evaluator/eval_inline_variable.html @@ -0,0 +1,46 @@ + + + + +Module eval_inline_variable + + + + +
    + +

    Module eval_inline_variable

    + +This modules substitutes variable occurrences by their value. +

    Copyright © (C) 2014, Gabriela C. Sampaio, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Authors: Gabriela Sampaio, Roberto Souto Maior.

    + +

    Description

    +This modules substitutes variable occurrences by their value.

    + + Only variables defined via a match expression of the format: VarName = Expr can be inlined. Consider the code below:
    + + begin
    +
    + X = 1,
    + Y = X + 2,
    + Y + 3
    +
    + end.
    +
    + This module, will simplify the previous expression to:
    + + begin
    +
    + X = 1,
    + Y = 1 + 2,
    + 1 + 2 + 3
    +
    + end.
    +

    + + +

    Generated by EDoc, Nov 5 2015, 16:30:16.

    + + diff --git a/docs/doc/symbolic_evaluation/evaluator/evaluator.html b/docs/doc/symbolic_evaluation/evaluator/evaluator.html new file mode 100644 index 00000000..19e88d7c --- /dev/null +++ b/docs/doc/symbolic_evaluation/evaluator/evaluator.html @@ -0,0 +1,53 @@ + + + + +Module evaluator + + + + +
    + +

    Module evaluator

    + +

    Copyright © (C) 2014, Gabriela C. Sampaio, Simon Thompson

    + +

    Authors: Gabriela Sampaio.

    + +

    Function Index

    + + +
    start/1 + This function starts the evaluator.
    start/2 + This function starts the evaluator.
    + +

    Function Details

    + +

    start/1

    +
    +

    start(DefFilesInp) -> any()

    +

    + This function starts the evaluator.
    + - DefFilesInp: list of atoms representing the names of the Erlang modules containing definitions. It is assumed, in this function, + that these files are in the current directory.

    + +

    start/2

    +
    +

    start(DefFilesInput, Options) -> any()

    +

    + This function starts the evaluator.
    + - DefFilesInput: list of atoms representing the names of the Erlang modules containing definitions.
    + - Options: a list of tuples. One tuple should represent the search paths and the other the timeout. They can be defined in any order + and each tuple should contain an atom specifying if is search paths or timeout and the respective value. If a timeout is defined, the + evaluation will not stop before this time. The search paths allow the user to choose which directory(ies) contain the Erlang file(s).
    + A possible call would be:
    + evaluator:start([file1,file2,...,fileN],[{timeout, Timeout},{search_paths,[Search_Path1,Search_Path2,...,Search_PathN]}],
    + where file1,file2,...,fileN, timeout and search_paths are atoms, Timeout is an integer representing the + timeout and Search_Path1, Search_Path2,..., Search_PathN are strings representing the search paths.

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:16.

    + + diff --git a/docs/doc/symbolic_evaluation/evaluator/index.html b/docs/doc/symbolic_evaluation/evaluator/index.html new file mode 100644 index 00000000..32bf8a84 --- /dev/null +++ b/docs/doc/symbolic_evaluation/evaluator/index.html @@ -0,0 +1,18 @@ + + + +The evaluator application + + + + + + + +<h2>This page uses frames</h2> +<p>Your browser does not accept frames. +<br>You should go to the <a href="overview-summary.html">non-frame version</a> instead. +</p> + + + diff --git a/docs/doc/symbolic_evaluation/evaluator/modules-frame.html b/docs/doc/symbolic_evaluation/evaluator/modules-frame.html new file mode 100644 index 00000000..fe939fcd --- /dev/null +++ b/docs/doc/symbolic_evaluation/evaluator/modules-frame.html @@ -0,0 +1,13 @@ + + + +The evaluator application + + + +

    Modules

    + + +
    eval_inline_variable
    evaluator
    + + \ No newline at end of file diff --git a/docs/doc/symbolic_evaluation/evaluator/overview-summary.html b/docs/doc/symbolic_evaluation/evaluator/overview-summary.html new file mode 100644 index 00000000..c01e32f6 --- /dev/null +++ b/docs/doc/symbolic_evaluation/evaluator/overview-summary.html @@ -0,0 +1,62 @@ + + + + +Erlang Teaching Tool for Symbolic Evaluation + + + + +

    Erlang Teaching Tool for Symbolic Evaluation

    +

    Copyright © 2014 Gabriela Sampaio, Simon Thompson

    +

    Authors: Gabriela Sampaio (gaby.sampaio@gmail.com), Simon Thompson (s.j.thompson@kent.ac.uk).

    +

    The Erlang Teaching Tool for Symbolic Evaluation was created +with the aim of teaching how expressions are evaluated in Erlang.

    + +

    Contents

    + +
      +
    1. Introduction
    2. +
    3. Download
    4. +
    5. Symbolic Transformations
    6. +
    7. How to use
    8. +
    + +

    Introduction

    +Symbolic evaluation is a form of static program execution in which symbolic expressions are used to represent arbitrary values of program variables and computations. This tool was created with the aim of teaching how expressions are evaluated in Erlang. The tool is able to evaluate not only arbitrary expressions, but also symbolic ones. The tool can be used by any Erlang programmer, but is more useful for beginners or teachers in the area. The idea is that the user can interact with the application by evaluating an expression step-by-step.

    +Symbolic transformations were created using Wrangler API. Wrangler is the refactoring tool for Erlang and it is user-extensible, i.e., users can create their own refactorings. With this possibility, some simplifications were built and are used in this project.

    + +

    Symbolic Transformations

    +Some symbolic transformations were created in the project. Expressions are simplified according to this set of transformations. To make the tool more organized and easier to understand, we divided the transformations into eight categories: + + +

    These simplifications are always used together. Thus, if the user types an expression that can be simplified by more than one type of evaluator, they are both used and each one simplifies a part of the expression.

    + +

    Download

    +The tool is distributed with the Wrangler tool. The user needs to download Wrangler from the Github website https://github.com/RefactoringTools/Wrangler, and run the evaluator in the Erlang shell.

    + +

    How to use

    +To use the evaluator, the user needs to have Wrangler and Erlang installed. The application works in the Erlang shell. To start the evaluator, one of the functions start/1 and start/2 should be called. This function is described in the Evaluator module. After the evaluator is started, two inputs are needed:
    +- An expression: the user should write Erlang files containing definitions (modules, functions) and ideally, this expression should use these definitions. The expression can be a function call, an arithmetic calculation, a lists concatenation, etc.
    +- A number of steps: the user can choose a number of steps to be applied in the evaluation process. This number can be:
    + *A positive number: steps are applied "forward" in the evaluation process.
    + *A negative number: the respective number of steps are undone.
    + *"F" or "f" (for "full"): all steps are applied.

    + +At the end of each iteration, the user has the chance to continue with the evaluation or start a new evaluation. If the user chooses to continue with the current evaluation, the only input requested is a new number of steps to be applied. Otherwise, the user chooses +a new expression to be evaluated and a new evaluation is started. + +
    + +

    Generated by EDoc, Nov 5 2015, 16:30:16.

    + + diff --git a/docs/doc/symbolic_evaluation/evaluator/stylesheet.css b/docs/doc/symbolic_evaluation/evaluator/stylesheet.css new file mode 100644 index 00000000..ab170c09 --- /dev/null +++ b/docs/doc/symbolic_evaluation/evaluator/stylesheet.css @@ -0,0 +1,55 @@ +/* standard EDoc style sheet */ +body { + font-family: Verdana, Arial, Helvetica, sans-serif; + margin-left: .25in; + margin-right: .2in; + margin-top: 0.2in; + margin-bottom: 0.2in; + color: #000000; + background-color: #ffffff; +} +h1,h2 { + margin-left: -0.2in; +} +div.navbar { + background-color: #add8e6; + padding: 0.2em; +} +h2.indextitle { + padding: 0.4em; + background-color: #add8e6; +} +h3.function,h3.typedecl { + background-color: #add8e6; + padding-left: 1em; +} +div.spec { + margin-left: 2em; + background-color: #eeeeee; +} +a.module { + text-decoration:none +} +a.module:hover { + background-color: #eeeeee; +} +ul.definitions { + list-style-type: none; +} +ul.index { + list-style-type: none; + background-color: #eeeeee; +} + +/* + * Minor style tweaks + */ +ul { + list-style-type: square; +} +table { + border-collapse: collapse; +} +td { + padding: 3 +} diff --git a/docs/doc/symbolic_evaluation/refactorings/erlang.png b/docs/doc/symbolic_evaluation/refactorings/erlang.png new file mode 100644 index 00000000..987a618e Binary files /dev/null and b/docs/doc/symbolic_evaluation/refactorings/erlang.png differ diff --git a/docs/doc/symbolic_evaluation/refactorings/index.html b/docs/doc/symbolic_evaluation/refactorings/index.html new file mode 100644 index 00000000..342fb5c0 --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/index.html @@ -0,0 +1,18 @@ + + + +The refactorings application + + + + + + + +<h2>This page uses frames</h2> +<p>Your browser does not accept frames. +<br>You should go to the <a href="overview-summary.html">non-frame version</a> instead. +</p> + + + diff --git a/docs/doc/symbolic_evaluation/refactorings/modules-frame.html b/docs/doc/symbolic_evaluation/refactorings/modules-frame.html new file mode 100644 index 00000000..abe4e25c --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/modules-frame.html @@ -0,0 +1,22 @@ + + + +The refactorings application + + + +

    Modules

    + + + + + + + + + + + +
    refac_all
    refac_arit_calc
    refac_arit_simpl
    refac_arithmetics
    refac_boolean_operators
    refac_case
    refac_funApp
    refac_if
    refac_inline_variable
    refac_lists_concat
    refac_unreferenced_assign
    + + \ No newline at end of file diff --git a/docs/doc/symbolic_evaluation/refactorings/overview-summary.html b/docs/doc/symbolic_evaluation/refactorings/overview-summary.html new file mode 100644 index 00000000..42ef71ac --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/overview-summary.html @@ -0,0 +1,48 @@ + + + + +Symbolic Evaluation Refactorings + + + + +

    Symbolic Evaluation Refactorings

    +

    Copyright © (C) 2014, Roberto S. M. de Barros Filho, Simon Thompson

    +

    Authors: Roberto Souto Maior de Barros Filho.

    +

    See also: gen_refac.

    + +This set of refactorings, uses Wrangler API, to propose a number of simplifications that perform symbolic evaluation in Erlang. More specifically, the following refactorings belong to these group: + + + + + + +
    + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_all.html b/docs/doc/symbolic_evaluation/refactorings/refac_all.html new file mode 100644 index 00000000..7ade3dd1 --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_all.html @@ -0,0 +1,34 @@ + + + + +Module refac_all + + + + +
    + +

    Module refac_all

    +All - Composed refactoring of all the other refactorings in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation. +

    Copyright © (C) 2013, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    All - Composed refactoring of all the other refactorings in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation -> All. + The rules of this refactoring, respect the following order: +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_arit_calc.html b/docs/doc/symbolic_evaluation/refactorings/refac_arit_calc.html new file mode 100644 index 00000000..f6604099 --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_arit_calc.html @@ -0,0 +1,31 @@ + + + + +Module refac_arit_calc + + + + +
    + +

    Module refac_arit_calc

    + + This module covers refactorings with arithmetic expressions. +

    Copyright © (C) 2013, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    + This module covers refactorings with arithmetic expressions. These expressions may contain variables and/or integers. +

    + Unfortunately, there are some cases that are still not being covered. +

    • For instance, if an expression contains integers and variables interchanged, as "1 + X + 1". In this case, this expression is not simplified anymore.
    • +
    • Multiplication and division between variables is also not covered.

    +

    However, if the expression contains integers and variables but they are not mixed, as in "1 + 2 + 3 + X + 2*X + Y", the refactoring can be done and the expression would become "6 + 3 * X + Y" for this example.


    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_arit_simpl.html b/docs/doc/symbolic_evaluation/refactorings/refac_arit_simpl.html new file mode 100644 index 00000000..64266fdc --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_arit_simpl.html @@ -0,0 +1,37 @@ + + + + +Module refac_arit_simpl + + + + +
    + +

    Module refac_arit_simpl

    + + These refactoring does arithmetic simplification modifications. +

    Copyright © (C) 2013, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    + These refactoring does arithmetic simplification modifications. +

    We can include here the following cases: +

      +
    • Sum by zero - Expressions of type "Exp + 0" and "0 + Exp" are transformed into "Exp". For example, X + 0 is modified to X.
    • +
    • Subtraction by zero - Subtractions with zero as the second operand are modified. For instance, Y - 0 becomes Y.
    • +
    • Subtraction from zero - Expressions that match "0 - Exp" are altered to "-Exp". To exemplify, 0 - Y is changed to -Y.
    • +
    • Multiplication by one - Expressions of the formats "Exp * 1" and "1 * Exp" are simplified to "Exp". To illustrate, Z * 1 is modified to Z.
    • +
    • Multiplication by zero - Multiplications containing zero as an operand are simplified to zero.
    • +
    • Division by one - Divisions by one, using the operator (div), are replaced by the numerator. For example, 3 div 1 is transformed to 3.
    • +
    +

    +

    These refactorings can only by applied to integers, variables and expressions formed by these two types.


    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_arithmetics.html b/docs/doc/symbolic_evaluation/refactorings/refac_arithmetics.html new file mode 100644 index 00000000..8c35e4ae --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_arithmetics.html @@ -0,0 +1,28 @@ + + + + +Module refac_arithmetics + + + + +
    + +

    Module refac_arithmetics

    + + Arithmetic Operators - Covers arithmetic expressions. +

    Copyright © (C) 2014, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    + Arithmetic Operators - Covers arithmetic expressions. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation -> Arithmetic Operators.

    + + For more details of the simplifications performed, please refer to Arithmetics Operators Core.
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_boolean_operators.html b/docs/doc/symbolic_evaluation/refactorings/refac_boolean_operators.html new file mode 100644 index 00000000..b480b191 --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_boolean_operators.html @@ -0,0 +1,28 @@ + + + + +Module refac_boolean_operators + + + + +
    + +

    Module refac_boolean_operators

    + + Boolean Operators - Simplifies the defined boolean operators to true or false. +

    Copyright © (C) 2014, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    + Boolean Operators - Simplifies the defined boolean operators to true or false. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation -> Boolean Operators.

    + + For more details of the transformation, please see Boolean Operators Core.
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_case.html b/docs/doc/symbolic_evaluation/refactorings/refac_case.html new file mode 100644 index 00000000..dafaa5fb --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_case.html @@ -0,0 +1,28 @@ + + + + +Module refac_case + + + + +
    + +

    Module refac_case

    + + Case - Where possible, simplifies case expressions by the result of their evaluation. +

    Copyright © (C) 2014, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    + Case - Where possible, simplifies case expressions by the result of their evaluation. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation -> Case.

    + + For more details on the alterations, please refer to Case Core.
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_funApp.html b/docs/doc/symbolic_evaluation/refactorings/refac_funApp.html new file mode 100644 index 00000000..a8fe4606 --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_funApp.html @@ -0,0 +1,51 @@ + + + + +Module refac_funApp + + + + +
    + +

    Module refac_funApp

    +Unfold Function Application - Substitute function calls by its application. +

    Copyright © (C) 2013, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    Unfold Function Application - Substitute function calls by its application. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation -> Unfold Function Application.

    + +

    Most of the transformation in this module are from Unfold Function Application Core.

    + +

    Nevertheless, the following simplification is also done in this module:

    + + Internal calls - Function application for function calls from internal modules. To illustrate, consider the following definition of the function double/1:

    + double(X) when is_number(X) -> 2 * X.

    + A call to double(2), within the same module that double/1 was defined, is modified to 2 * 2. +

    Function Index

    + +
    rules/2 + Return the list of rules for the function application refactoring.
    + +

    Function Details

    + +

    rules/2

    +
    +

    rules(X1::{{InternalInfo::[{mfa(), syntaxTree(), [syntaxTree()], syntaxTree()}], ExternalInfo::[{mfa(), syntaxTree(), [syntaxTree()], syntaxTree()}] | [{list, [{modulename(), [{mfa(), syntaxTree(), [syntaxTree()], syntaxTree()}]}]}]}, term(), BoundVars::[{atom(), pos()}]}, FunDefInfo::mfa() | unknown) -> [rule()]

    +

    + Return the list of rules for the function application refactoring. This is formed by: +

      +
    • core_funApp:length_rule/0
    • +
    • core_funApp:functionCall_rule/4
    • +
    • Internal calls rule
    • +
    • core_funApp:anonymousCall_rule/0
    • +

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_if.html b/docs/doc/symbolic_evaluation/refactorings/refac_if.html new file mode 100644 index 00000000..afb1a932 --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_if.html @@ -0,0 +1,28 @@ + + + + +Module refac_if + + + + +
    + +

    Module refac_if

    + + If - Where possible, simplifies if expressions by the result of their evaluation. +

    Copyright © (C) 2014, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    + If - Where possible, simplifies if expressions by the result of their evaluation. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation -> If.

    + + For examples of simplifications, please refer to If Core.
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_inline_variable.html b/docs/doc/symbolic_evaluation/refactorings/refac_inline_variable.html new file mode 100644 index 00000000..bf25e437 --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_inline_variable.html @@ -0,0 +1,33 @@ + + + + +Module refac_inline_variable + + + + +
    + +

    Module refac_inline_variable

    + + Inline Variable - Inline a variable definition. +

    Copyright © (C) 2014, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    + Inline Variable - Inline a variable definition. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Inline Variable.

    + +

    To unfold instances of a variable, point the cursor to the variable assignment and the select + Inline Variable from the item gen_refacs in the Wrangler Refactor menu. + After that, Wrangler will search for the occurrences of the selected variable and let you choose which instance to unfold. + Only variables defined via a match expression of the format: VarName = Expr can be inlined.

    + + If the user chooses to inline all instances of a variable, the match expression is also removed.
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_lists_concat.html b/docs/doc/symbolic_evaluation/refactorings/refac_lists_concat.html new file mode 100644 index 00000000..2251eedb --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_lists_concat.html @@ -0,0 +1,28 @@ + + + + +Module refac_lists_concat + + + + +
    + +

    Module refac_lists_concat

    + + Lists Concatenation - Simplifies lists concatenations. +

    Copyright © (C) 2014, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    + Lists Concatenation - Simplifies lists concatenations. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation -> Lists Concatenation.

    + + For more details of the transformation, please refer to Lists Concatenation Core.
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/refac_unreferenced_assign.html b/docs/doc/symbolic_evaluation/refactorings/refac_unreferenced_assign.html new file mode 100644 index 00000000..0ea65411 --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/refac_unreferenced_assign.html @@ -0,0 +1,65 @@ + + + + +Module refac_unreferenced_assign + + + + +
    + +

    Module refac_unreferenced_assign

    + + Remove Unreferenced Assignments - Removes assignments when the variables are not used afterwards. +

    Copyright © (C) 2014, Roberto S. M. de Barros Filho, Simon Thompson

    + +

    Behaviours: gen_refac.

    +

    Authors: Roberto Souto Maior de Barros Filho.

    + +

    Description

    + Remove Unreferenced Assignments - Removes assignments when the variables are not used afterwards. This refactoring uses Wrangler API and can be found in Wrangler -> Refactor -> gen_refac Refacs -> Symbolic Evaluation -> Remove Unreferenced Assignments.

    + + For example, the expression:
    + + begin
    +
    + A = 10,
    + B = 20,
    + C = 30,
    + E = A + B + C,
    + A
    +
    + end.
    +
    + can be simplified by this refactoring to:
    + + begin
    +
    + A = 10,
    + A
    +
    + end.
    +
    +

    Function Index

    + +
    rules/2 + List of rules that remove unreferenced assignments for this refactoring.
    + +

    Function Details

    + +

    rules/2

    +
    +

    rules(CollectResult::{modulename(), {mfa() | unknown, [syntaxTree()], [[syntaxTree()]], [[{atom(), pos()}]], [syntaxTree()]}}, FunInfo::{function | project | file, mfa() | unknown}) -> [rule()]

    +

    + List of rules that remove unreferenced assignments for this refactoring. The following rules exist: +

      +
    • Removes unreferenced assignments in the list of steps of the function clause.
    • +
    • Removes unreferenced assignments in more internal structures, like list of steps within if/case expressions.
    • +

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:17.

    + + diff --git a/docs/doc/symbolic_evaluation/refactorings/stylesheet.css b/docs/doc/symbolic_evaluation/refactorings/stylesheet.css new file mode 100644 index 00000000..ab170c09 --- /dev/null +++ b/docs/doc/symbolic_evaluation/refactorings/stylesheet.css @@ -0,0 +1,55 @@ +/* standard EDoc style sheet */ +body { + font-family: Verdana, Arial, Helvetica, sans-serif; + margin-left: .25in; + margin-right: .2in; + margin-top: 0.2in; + margin-bottom: 0.2in; + color: #000000; + background-color: #ffffff; +} +h1,h2 { + margin-left: -0.2in; +} +div.navbar { + background-color: #add8e6; + padding: 0.2em; +} +h2.indextitle { + padding: 0.4em; + background-color: #add8e6; +} +h3.function,h3.typedecl { + background-color: #add8e6; + padding-left: 1em; +} +div.spec { + margin-left: 2em; + background-color: #eeeeee; +} +a.module { + text-decoration:none +} +a.module:hover { + background-color: #eeeeee; +} +ul.definitions { + list-style-type: none; +} +ul.index { + list-style-type: none; + background-color: #eeeeee; +} + +/* + * Minor style tweaks + */ +ul { + list-style-type: square; +} +table { + border-collapse: collapse; +} +td { + padding: 3 +} diff --git a/docs/doc/wrangler_gen.html b/docs/doc/wrangler_gen.html new file mode 100644 index 00000000..5214dde5 --- /dev/null +++ b/docs/doc/wrangler_gen.html @@ -0,0 +1,119 @@ + + + + +Module wrangler_gen + + + + +
    + +

    Module wrangler_gen

    +This module specifies a suite of refactoring command generators. + + +

    Description

    This module specifies a suite of refactoring command generators. + The command generators provided by this modules are used for scripting + composite refactorings. For details on how to script composite + refactorings, see Gen_Composite_Refac +

    Data Types

    + +

    fa()

    +

    fa() = fun(({FunName::atom(), Arity::integer()}) -> boolean()) | {atom(), integer()}

    + + +

    file_filter()

    +

    file_filter() = {file, fun((File::filename()) -> boolean())}

    + + +

    generator()

    +

    generator() = {lazy_gen, function()}

    + + +

    lazy_refac()

    +

    lazy_refac() = {elementary_refac(), generator()}

    + + +

    mod_or_file()

    +

    mod_or_file() = file_filter() | module_filter() | atom() | filename()

    + + +

    module_filter()

    +

    module_filter() = {module, fun((Mod::atom()) -> boolean())}

    + + +

    search_paths()

    +

    search_paths() = [filename() | dir()]

    + + +

    Function Index

    + + + + + + + + + + +
    add_to_export/4Command generator for adding function names to the export list of a module.
    fold_expr/6Command generator for folding expressions against a function definition.
    gen_fun/7Command generator for function generalisation.
    move_fun/5Command generator for moving functions from one module to another.
    rename_fun/5Command generator for renaming function names.
    rename_mod/4Command generator for renaming module names.
    rename_var/6Command generator for renaming variable names.
    swap_args/6Command generator for for swapping function arguments.
    tuple_args/6Command generator for tupling function arguments.
    unfold_fun_app/5Command generator for unfolding a function application.
    + +

    Function Details

    + +

    add_to_export/4

    +
    +

    add_to_export(ModOrFile::mod_or_file(), Fa::fa(), Lazy::boolean(), SearchPaths::search_paths()) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for adding function names to the export list of a module.

    + +

    fold_expr/6

    +
    +

    fold_expr(CurModOrFile::mod_or_file(), ModOrFile::mod_or_file(), FA::fa(), ClauseIndex::integer(), Lazy::boolean(), SearhPaths::search_paths()) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for folding expressions against a function definition.

    + +

    gen_fun/7

    +
    +

    gen_fun(ModOrFile::mod_or_file(), FA::fa(), ExprStr::string(), NewParName::{user_input, Prompt::fun(({M::atom(), FA::{atom(), integer()}, ExprStr::string()}) -> string())} | atom() | string(), Lazy::boolean(), SearchPaths::search_paths(), GenOrder::textual | bu | td) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for function generalisation.

    + +

    move_fun/5

    +
    +

    move_fun(SrcModOrFile::mod_or_file(), Fa::fa(), TagertModOrFile::mod_or_file() | {user_input, Prompt::fun(({M::atom(), FA::{atom(), integer()}}) -> string())}, Lazy::boolean(), SearchPaths::search_paths()) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for moving functions from one module to another.

    + +

    rename_fun/5

    +
    +

    rename_fun(ModOrFile::mod_or_file(), Fa::fa(), NewFunName::{generator, fun(({M::atom(), FA::{atom(), integer()}}) -> atom())} | {user_input, Prompt::fun(({M::atom(), FA::{atom(), integer()}}) -> string())} | atom(), Lazy::boolean(), SearchPaths::search_paths()) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for renaming function names.

    + +

    rename_mod/4

    +
    +

    rename_mod(ModOrFile::mod_or_file(), NewModName::{generator, fun((M::atom() | filename()) -> string())} | {user_input, Prompt::fun((M::atom()) -> string())} | string(), Lazy::boolean(), SearchPaths::search_paths()) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for renaming module names.

    + +

    rename_var/6

    +
    +

    rename_var(ModOrFile::mod_or_file(), FA::fa(), OldVarName::fun((VarName::atom()) -> boolean()) | atom(), NewVarName::{generator, fun(({M::atom(), FA::{atom(), integer()}, V::atom()}) -> atom())} | {user_input, Prompt::fun(({M::atom(), FA::{atom(), integer()}, V::atom()}) -> string())} | atom(), Lazy::boolean(), SearchPaths::search_paths()) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for renaming variable names.

    + +

    swap_args/6

    +
    +

    swap_args(ModOrFile::mod_or_file(), FA::fa(), Index1::integer() | {user_input, Prompt::fun(({M::atom(), FA::{atom(), integer()}}) -> string())}, Index2::integer() | {user_input, Prompt::fun(({M::atom(), FA::{atom(), integer()}}) -> string())}, Lazy::boolean(), SearchPaths::search_paths()) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for for swapping function arguments.

    + +

    tuple_args/6

    +
    +

    tuple_args(ModOrFile::mod_or_file(), FA::fa(), Index1::integer() | {user_input, Prompt::fun(({M::atom(), FA::{atom(), integer()}}) -> string())}, Index2::integer() | {user_input, Prompt::fun(({M::atom(), FA::{atom(), integer()}}) -> string())}, Lazy::boolean(), SearchPaths::search_paths()) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for tupling function arguments.

    + +

    unfold_fun_app/5

    +
    +

    unfold_fun_app(ModOrFile::mod_or_file(), FA::fa(), MFAorPos::fun((mfa()) -> boolean()) | mfa() | pos(), Lazy::boolean(), SearchPaths::search_paths()) -> [elementary_refac()] | lazy_refac()

    +

    Command generator for unfolding a function application.

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:21.

    + + diff --git a/docs/doc/wrangler_refacs.html b/docs/doc/wrangler_refacs.html new file mode 100644 index 00000000..286f34b9 --- /dev/null +++ b/docs/doc/wrangler_refacs.html @@ -0,0 +1,624 @@ + + + + +Module wrangler_refacs + + + + +
    + +

    Module wrangler_refacs

    +This module describes the refactorings that are currently supported by Wrangler. +

    Copyright © 2006-2012 Huiqing Li, Simon Thompson +

    + +

    Authors: Huiqing Li, Simon Thompson [web site: http://www.cs.kent.ac.uk/projects/wrangler].

    + +

    Description

    This module describes the refactorings that are currently supported by Wrangler. + The refactoring functions listed in this module are NOT supposed to be run in an + Erlang shell. Interface for refactorings that can be run in an Erlang shell are + documented in module api_wrangler. +

    Data Types

    + +

    context()

    +

    context() = emacs | composite_emacs | command

    + + +

    Function Index

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    add_a_tag/7Add a tag to all the messages received by a server process (Beta).
    add_callback/6 + Adds a callback declaration for the function with the name + and arity specified.
    add_callbacks/5 + Adds a callback declaration for the functions with the name + specified.
    apply_changes_eclipse/3gen_refac refactorings - delegate functions in order to achieve more clear API (especially for Eclipse).
    copy_mod/5Copy a module.
    eqc_fsm_to_record/4Turn a non-record representation of eqc_fsm state into a record representation.
    eqc_statem_to_record/4Turn a non-record representation of eqc_statem state into a record representation.
    fold_against_macro/6Fold expressions/patterns against a macro definition.
    fold_expr/1Fold expressions against a function definition.
    fun_extraction/6Introduce a new function to represent an expression or expression sequence.
    fun_to_process/7Turn a function into a server process (Beta).
    gen_fsm_to_record/4Turn a non-record representation of gen_fsm state into a record representation.
    generalise/7 Generalise a function definition.
    get_user_refactorings/1get all user refactoring modules (gen_refac and gen_composite_refac).
    inline_var/6Inline a variable definition.
    intro_new_var/7Introduce a new variable to represent an expression selected.
    merge_forall/4Merge nested but undependent ?FORALLs into one ?FORALL.
    merge_let/4Merge nested but independent ?LETs into one ?LET.
    move_fun/7Move a function definition from its current module to another.
    new_let/7Introduce ?LET.
    new_macro/7Introduce a macro to represent a syntactically well-formed expression/pattern or a sequence of expressions/patterns.
    normalise_record_expr/7Reorder the record fields in a record expression to be consistent with the record definition.
    partition_exports/5Partition the exports of a module.
    register_pid/7Register a process (Beta).
    rename_fun/6Rename a function.
    rename_mod/5Rename a module.
    rename_process/7Rename a registered process (Beta).
    rename_var/7Rename a variable.
    similar_code_detection/6A similar code detector that searches for similar code across multiple Erlang modules.
    similar_code_detection_in_buffer/6A similar code detector that searches for similar code in the current Erlang buffer.
    similar_expression_search_in_buffer/6Search expression search in the current Erlang buffer.
    similar_expression_search_in_dirs/6Simiar expression search across multiple Erlang modules.
    tuple_funpar/6Group a consecutive sequence of parameters of a function into a tuple.
    unfold_fun_app/5Unfold a function application to an instance of the function's body.
    + +

    Function Details

    + +

    add_a_tag/7

    +
    +

    add_a_tag(FileName::filename(), Line::integer(), Col::integer(), Tag::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, [filename()]}

    +

    Add a tag to all the messages received by a server process (Beta). +

    This refactoring should be initiated from the main receive function of a server process. + The current implementation is still in an experimental stage, and has a number of limitations: +

  • The current implementation assumes that the process does not send inquiries, + using the send ... receive pattern, to other processes +
  • +
  • The current implementation only handles processes spawned using spawn + or spawn_link +
  • +

    +

    + Usage: to apply this refactoring, point the cursor to the function name, then select Add a + Tag to Messages from the Refactor menu, Wrangler will then prompt to + enter the tag. +

    + +

    add_callback/6

    +
    +

    add_callback(TargetFileName::string(), FunctionName::string(), Arity::string(), SearchPaths::[string()], Editor::wrangler_refacs:context(), TabWidth::integer()) -> {ok, UpdatedFiles::[string()]}

    +

    + Adds a callback declaration for the function with the name + and arity specified.

    + +

    add_callbacks/5

    +
    +

    add_callbacks(TargetFileName::string(), FunctionName::string(), SearchPaths::[string()], Editor::wrangler_refacs:context(), TabWidth::integer()) -> {ok, UpdatedFiles::[string()]}

    +

    + Adds a callback declaration for the functions with the name + specified.

    + +

    apply_changes_eclipse/3

    +
    +

    apply_changes_eclipse(Module::module(), Args::[term()], CandsNotToChange::[term()]) -> {ok, [{filename(), filename(), syntaxTree()}]} | {error, term()}

    +

    gen_refac refactorings - delegate functions in order to achieve more clear API (especially for Eclipse)

    + +

    copy_mod/5

    +
    +

    copy_mod(FileName::filename(), NewName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {question, string()} | {warning, string()} | {ok, [filename()]}

    +

    Copy a module. +

    This refactoring affects all those modules in which the module name is used. +

    +

    + The following side-conditions apply to this refactoring: +

  • The new module name should not have been used as a module name in the program under consideration.
  • +
  • This refactoring assume that the file basename is always the same as the module name, therefore this + refactoring changes the filename as well.
  • +

    +

    Usage: to apply this refactoring, point the cursor anywhere in the module to be copied, then select + Copy Module from the Refactor menu, after that, the refactorer will prompt to enter + the new module name in the mini-buffer. +

    + +

    eqc_fsm_to_record/4

    +
    +

    eqc_fsm_to_record(FileName::filename(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, non_tuple, [{atom(), atom(), integer()}]} | {ok, {tuple, integer()}, [{atom(), atom(), integer()}]}

    +

    Turn a non-record representation of eqc_fsm state into a record representation. +

    This refactoring introduce a record to represent the state used by eqc_fsm. + This refactoring is especially for QuickCheck users. +

    +

    Usage: Select the refactoring command, and Wrangler will check the current type of the state machine, + and prompt you to input the record and field names if Wrangler is able to proceed the refactoring. +

    + +

    eqc_statem_to_record/4

    +
    +

    eqc_statem_to_record(FileName::filename(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, non_tuple, [{atom(), atom(), integer()}]} | {ok, {tuple, integer()}, [{atom(), atom(), integer()}]}

    +

    Turn a non-record representation of eqc_statem state into a record representation. +

    This refactoring introduce a record to represent the state used by eqc_statem. + This refactoring is especially for QuickCheck users. +

    +

    Usage: Select the refactoring command, and Wrangler will check the current type of the state machine, + and prompt you to input the record and field names if Wrangler is able to proceed the refactoring. +

    + +

    fold_against_macro/6

    +
    +

    fold_against_macro(FileName::filename(), Line::integer(), Col::integer(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, [{integer(), integer(), integer(), integer(), syntaxTree(), syntaxTree()}], string()}

    +

    Fold expressions/patterns against a macro definition. +

    + This refactoring replaces instances of the right-hand side of a macro definition by the corresponding + left-hand side with necessary parameter substitutions. +

    +

    Usage: to apply this refactoring, first point the cursor to the macro definition against which candidate + expressions/candidates will be folded; then select Fold Against Macro Definition from the + Refactor menu; after that, Wrangler will search the current module for expressions/patterns + which are instances of the right-hand side of the selected macro definition; and direct you through the + refactoring process. +

    + +

    fold_expr/1

    +
    +

    fold_expr(X1) -> any()

    +

    Fold expressions against a function definition. +

    + This refactoring replaces instances of the right-hand side of a function clause definition by + the corresponding left-hand side with necessary parameter substitutions. The function clause can + be defined in either the current module or another module. +

    +

    In the case that a candidate expression/expression sequence needs to export some variables which + are used by the code following code, that expression/expression sequence will be replaced by a match + expression, whose left-hand side it the exported variable(s), and right-hand side is the function + application. +

    +

    This refactoring does not support folding against function clauses with guard expressions, or + function clauses with complex formal parameters, such as tuples, lists, or records. +

    +

    Usage: first point the cursor to the function clause against which expressions will be + folded if the function is defined in the current module, or leave the cursor anywhere if you would like to + fold against a function clause defined in another module; then select Fold Expression Against Function + from the Refactor menu; after that, Wrangler then asks to confirm that you want to fold against + the function clause pointed to by the cursor, if you answer 'no', Wrangler will prompt to provide the + module name, function name, arity of the function and the index of the function clause (starting from 1). After all these initial interaction, + Wrangler will search + the current module for expressions which are instances of the right-hand side of the selected function clause. +

    +

    If no candidate expression has been found, a message will be given, and the refactoring + finishes; otherwise, Wrangler will go through the found candidate expressions one by one, and ask + the user whether she/he wants to replace the expression with an application of selected function. + If the user answers 'yes' to one instance, that instance will be replaced by function application, + otherwise it will remain unchanged. +

    + +

    fun_extraction/6

    +
    +

    fun_extraction(FileName::filename(), Start::[integer()], End::[integer()], FunName::string(), Context::context(), TabWidth::integer()) -> {error, string()} | {warning, string()} | {ok, [filename()]}

    +

    Introduce a new function to represent an expression or expression sequence. +

    This refactoring allows the user to introduce a new function to represent a selected expression or expression + sequence, and replace the selected code with a call to the new function. Free variables + within the selected code become the formal parameters of the function definition. +

    +

    + Usage: highlight the expression/expression sequence of interest, then selected the Function Extraction + from Refactor, Wrangler will then prompt for the new function name. +

    + +

    fun_to_process/7

    +
    +

    fun_to_process(FileName::filename(), Line::integer(), Col::integer(), ProcessName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {ok, [filename()]} | {undecidables, string()} | {error, string()}

    +

    Turn a function into a server process (Beta). +

    + This refactoring turns a function into a server process. + Turning a function into a server process provides potential for memorisation of calculated values, adding states to the process, etc. +

    +

    The following example shows the application of this refactoring to the function f/2 on the + left-hand side, and the result is shown on the right-hand side. +

             f(add, X, Y) ->  X + Y;                     f(add, X, Y) -> f_rpc(f, {add, X, Y});
    +         f(sub, X, Y) ->  X - Y.                     f(sub, X, Y) -> f_rpc(f, {sub, X, Y}).
    + 
    +         g(X, Y) ->                                  f() ->
    +              f(add, X, Y)*f(sub, X, Y).		   receive
    +                                                           {From, {add, X, Y}} -> From ! {f, X + Y}, f();
    +                                                           {From, {sub, X, Y}} -> From ! {f, X - Y}, f()
    +                                                          end.
    + 
    +                                                     f_rpc(RegName, Request) ->
    +                                                          Sender = self(),
    +                                                          Fun = fun () ->
    +  		                                                    try
    +  		                                                       register(RegName, self())
    +  		                                                    of
    +  		                                                      true -> Sender ! {started, self()}, f()
    +  		                                                    catch
    +  		                                                      error:_ ->
    +  			                                                   Sender ! {already_running, self()},
    +                                                                          already_running
    +  		                                                    end
    +  	                                                         end,
    +                                                          Pid = spawn(Fun),
    +                                                          receive {_, Pid} -> ok end,
    +                                                          RegName ! {self(), Request},
    +                                                          receive {RegName, Response} -> Response end.
    + 
    +                                                     g(X, Y) ->
    +                                                          f(add, X, Y) *f(sub, X, Y).
    +

    + The following side-conditions apply to this refactoring: +

    +

  • The process name provided by the user should be lexically legal, and not conflict with existing process names.
  • +
  • The function should not be a recursive function, either directly or indirectly.
  • +
  • The current function or functions called by this function should not register the Pid returned by self().
  • +

    +

    + Wrangler generates the new function name and the rpc function name automatically, but the user could always rename it afterwards. + Suppose the original function is f/n, then the new function name would be f/0 and the rpc + function name would be f_rpc/2; if any conflicts occur, '_i' will be attached to the end of the function + name where i is a smallest number that makes the name fresh. +

    +

    Usage: To apply this refactoring, point the cursor to the function of interest, then select + From Function to Process from Refactor, after that Wrangler will prompt + to enter the process registration name in the mini-buffer. +

    + +

    gen_fsm_to_record/4

    +
    +

    gen_fsm_to_record(FileName::filename(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, non_tuple, [{atom(), atom(), integer()}]} | {ok, {tuple, integer()}, [{atom(), atom(), integer()}]}

    +

    Turn a non-record representation of gen_fsm state into a record representation. +

    This refactoring introduce a record to represent the state used by eqc_statem. +

    +

    Usage: Select the refactoring command, and Wrangler will check the current type of the state machine, + and prompt you to input the record and field names if Wrangler is able to proceed the refactoring. +

    + +

    generalise/7

    +
    +

    generalise(FileName::filename(), Start::[integer()], End::[integer()], ParName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {ok, [filename()]} | {error, string()} | {multiple_instances, {atom(), atom(), integer(), pos(), syntaxTree(), boolean(), [{pos(), pos()}], string()}} | {unknown_side_effect, {atom(), atom(), integer(), pos(), syntaxTree(), integer(), [{pos(), pos()}], [{pos(), pos()}], string()}} | {more_than_one_clause, {atom(), atom(), integer(), pos(), syntaxTree(), boolean(), [{pos(), pos()}], [{pos(), pos()}], string()}}

    +

    Generalise a function definition. +

    Generalise a function definition by selecting a sub-expression of its right-hand + side and making this the value of a new argument added to the definition of the function. + The sub-expression becomes the actual parameter at the call sites.

    + +

    Here is an example of generalisation, in which the function add_one defined + on the left-hand side is generalised on the expression 1 , and the result is + shown on the right-hand side. + +

                    -module (test).                          -module (test).
    +                -export([f/1]).                          -export([f/1]).
    + 
    +                add_one ([H|T]) ->                       add_one (N, [H|T]) ->
    +                   [H+1 | add_one(T)];                      [H+N | add_one(N,T)];
    +                add_one ([]) -> [].                      add_one (N, []) -> [].
    + 
    +                f(X) -> add_one(X).                      f(X) -> add_one(1,X)
    +

    + +

    In the case that the selected expression has a side-effect, the refactorer will wrap this expression + in an function expression before passing it as the actual parameter to the call-sites. This is illustrated + in the following example, in which function repeat/1 is generalised on the expression + io:format("Hello\n"). + +

                    -module (test).                          -module (test).
    +                -export([f/0]).                          -export([f/0]).
    + 
    +                repeat(0) -> ok;                         repeat(A, 0) -> ok;
    +                repeat(N) ->                             repeat(A, N) ->
    +                  io:format("Hello\n"),                    A( ),
    +                  repeat(N-1).                             repeat(A,N-1).
    + 
    +                f() -> repeat(5).                        f( ) ->
    +                                                            repeat (fun( )->io:format ("Hello\n") end, 5).
    +

    + +

    This refactoring only affects the module in which the refactoring is initialised. In the case that + the generalised function is exported by the module, an auxiliary function will be created + to wrap the generalised function up, so that the module's interface is not changed. +

    +

    The following side-conditions apply to this refactoring: +

  • Suppose the function to be generalised is foo/n , then foo/n+1 should not + be in scope before the generalisation;
  • +
  • The new parameter name provided by the user should not conflict with the existing parameters or + change the semantics of the function to be generalised.
  • +

    +

    Usage: to apply this refactoring, highlight the expression first, then select + Generalise Function Definitio5n from the Refactor menu, after + that the refactorer will prompt to enter the parameter name in the mini-buffer.

    + + NOTE: in Erlang some literal expressions can not be replaced by variables. For example, the atom fields + in the expression record_info(fields, Record) should not be replaced by a variable or other expressions. + This kind of checking is NOT supported by Wrangler yet.

    + +

    get_user_refactorings/1

    +
    +

    get_user_refactorings(Modules) -> any()

    +

    get all user refactoring modules (gen_refac and gen_composite_refac)

    + +

    inline_var/6

    +
    +

    inline_var(FName::filename(), Line::integer(), Col::integer(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, string()} | {ok, [{pos(), pos()}], string()}

    +

    Inline a variable definition. +

    To unfold a particular use instance of a variable, point the cursor to that instance, and then select + Inline Variable from the Refactor menu; to unfold some, or all, use instances of + a variable, point the cursor to the define occurrence of the variable, then select Inline Variable + from the Refactor menu, Wrangler will search for the use occurrences of the variable selected, and + let you choose which instances to unfold. Only variables defined via a match expression of the + format: VarName=Expr can be inlined. +

    + +

    intro_new_var/7

    +
    +

    intro_new_var(FileName::filename(), Start::[integer()], End::[integer()], NewVarName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, string()}

    +

    Introduce a new variable to represent an expression selected. +

    + Usage: Highlight the expression of interest, then selected the Introduce New Variable + from Refactor, Wrangler will then prompt for the new variable name. +

    + +

    merge_forall/4

    +
    +

    merge_forall(FileName::filename, SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {not_found, string()} | {ok, [{integer(), integer(), integer(), integer(), string()}], string()}

    +

    Merge nested but undependent ?FORALLs into one ?FORALL. +

    This refactoring combines multiple nested, but undependent, ?FORALLs into one; the latter representation has + better shrinking performance. This refactoring is especially for QuickCheck users. +

    +

    + Usage: Select the refactoring command, and Wrangler will search for candidates to merge automatically, + guide you through the candidates found one by one, and ask you to decide whether to merge. +

    + +

    merge_let/4

    +
    +

    merge_let(FileName::filename, SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {not_found, string()} | {ok, [{integer(), integer(), integer(), integer(), string()}], string()}

    +

    Merge nested but independent ?LETs into one ?LET. +

    This refactoring combines multiple nested, but undependent, ?LETs into one; the latter representation has + better shrinking performance. This refactoring is especially for QuickCheck users. +

    +

    + Usage: Select the refactoring command, and Wrangler will search for candidates to merge automatically, + guide you through the candidates found one by one, and ask you to decide whether to merge. +

    + +

    move_fun/7

    +
    +

    move_fun(FileName::filename(), Line::integer(), Col::integer(), TargetModName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {ok, [filename()]} | {question, string()} | {error, string()}

    +

    Move a function definition from its current module to another. +

    This refactoring has a global effect, i.e., it affects all the modules in which + the function is imported/used. +

    +

    This refactoring assumes that an Erlang module name always matches its file name. +

    +

    Suppose we move function foo/n from its current module M + to module N , then the following side-conditions apply to + this refactoring: +

  • If foo/n is already in scope in module N , then its defining + module should be M . +
  • +
  • Function foo/n should not contain any uses of implicit fun expressions (Note: move a + collection of functions together to another module will be supported by another refactoring). +
  • +

    +

    Usage: to apply this refactoring, point the cursor at the function definition, then + select Move Definition to Another Module from the Refactor menu, + Wrangler will then prompt to enter the target module name in the mini-buffer. +

    + +

    new_let/7

    +
    +

    new_let(FileName::filename(), Start::[integer()], End::[integer()], PatName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, [filename()]} | {question, string(), list(), list(), string()}

    +

    Introduce ?LET. +

    Bind the values generated by a generator to a variable, so that the values generated by + the generator can be referred by other generators. The refactoring helps to introduce dependency + between QuickCheck generators. This refactoring is especially for QuickCheck users. +

    +

    + Usage: highlight the expression, which should be a QuickCheck generator, then select the + refactoring command, you will be prompted for the pattern variable name. +

    + +

    new_macro/7

    +
    +

    new_macro(FileName::filename(), Start::[integer()], End::[integer()], MacroName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, string()}

    +

    Introduce a macro to represent a syntactically well-formed expression/pattern or a sequence of expressions/patterns. +

    This refactoring allows the user to define a new macro to represent a expression/pattern or sequence + of expressions/patterns selected by the user, and replace the selected code with an application of the macro. + Free variables within the selected code become the formal parameters of the macro definition. +

    +

    + Usage: Highlight the expression of interest, then selected the Introduce a Macro + from Refactor, Wrangler will then prompt for the new macro name. +

    + +

    normalise_record_expr/7

    +
    +

    normalise_record_expr(FileName::filename(), Line::integer(), Col::integer(), ShowDefault::boolean(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, [filename()]}

    +

    Reorder the record fields in a record expression to be consistent with the record definition. +

    + Usage: point cursor to the record expression interested, then select Normalise Record Expression from Refactor. +

    + +

    partition_exports/5

    +
    +

    partition_exports(File::filename(), DistTreshold::string(), SearchPaths::[filename() | dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, [filename()]}

    +

    Partition the exports of a module.

    + +

    register_pid/7

    +
    +

    register_pid(FileName::filename(), Start::[integer()], End::[integer()], RegName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, [filename()]}

    +

    Register a process (Beta). +

    This refactoring registers a process id, Pid say, with a name, regname say, and replaces + the uses of Pid ! Msg with regname ! Msg whenever it is possible. +

    +

    + The following side-conditions apply to this refactoring: +

  • The process name provided by the user should be lexically valid.
  • +
  • The name provided by the user should not have been used as a process name.
  • +
  • The process under consideration should not have been registered.
  • +
  • Only one process spawned by the spawn expression selected should exist anytime during the running of the system.
  • +

    +

    + Usage: First select a match expression whose left-hand side is a process identifier, and right-hand side is a spawn expression, + then select Register a Process command from the Refactor menu, after that, Wrangler will prompt for the + process name. +

    + +

    rename_fun/6

    +
    +

    rename_fun(ModOrFileName, X2, NewFunName, SearchPaths, Editor, TabWidth) -> any()

    +

    Rename a function. +

    + When renaming an exported function, this refactoring has a global effect, that is, + it affects all those modules in which this function is imported/used. +

    +

    The following side-conditions (or pre-conditions} apply to this refactoring: +

  • The new function name should not cause confliction with any of the functions which are in scope in the + current module;
  • +
  • In the case that the function to be renamed is imported by another module, the new function name (with the same + arity) should not be already in scope (either defined or imported) in that module.
  • +

    +

    Usage: to apply this refactoring, point the cursor to any occurrence of this + function name, then select Rename Function Name from the Refactor menu, + after that, Wrangler will prompt to enter the new function name in the mini-buffer. +

    + +

    rename_mod/5

    +
    +

    rename_mod(FileName::filename(), NewName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {question, string()} | {warning, string()} | {ok, [filename()]}

    +

    Rename a module. +

    This refactoring affects all those modules in which the module name is used. +

    +

    + The following side-conditions apply to this refactoring: +

  • The new module name should not have been used as a module name in the program under consideration.
  • +
  • This refactoring assume that the file basename is always the same as the module name, therefore this + refactoring changes the filename as well.
  • +

    +

    Usage: to apply this refactoring, point the cursor anywhere in the module to be renamed, then select + Rename Module Name from the Refactor menu, after that, the refactorer will prompt to enter + the new module name in the mini-buffer. +

    + +

    rename_process/7

    +
    +

    rename_process(FileName::filename(), Line::integer(), Col::integer(), NewName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {undecidables, string()} | {ok, [filename()]}

    +

    Rename a registered process (Beta). +

    This refactoring has a global effect, i.e. it needs to check the whole program for places where the + original process name is used. +

    +

    The following side-conditions apply to this refactoring: +

  • The new process name should not be the atom 'undefined'
  • +
  • The new process name should not have been used as a process name in the program under consideration.
  • +
  • Since there are some cases where Wrangler cannot infer whether an atom represents a process name or not, for example, + a process name in a message, it would be help the refactoring process to select the process name from expressions, such as + registration expressions, where it is easier for Wrangler to infer that the atom is a process name.
  • +

    +

    Usage: To apply this refactoring, point the cursor to the process name, then select + Rename a Process from the Refactor menu, after that, Wrangler will prompt + to enter the new process name in the mini-buffer. +

    + +

    rename_var/7

    +
    +

    rename_var(FileName::filename(), Line::integer(), Col::integer(), NewName::string(), SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, filename()}

    +

    Rename a variable. +

    This refactoring has a local effect, i.e., it only affects the function clause in which the refactoring is initialized. +

    +

    The following side-conditions (or pre-conditions) apply to this refactoring: +

  • The new variable name should not conflict with any of the declared variable names in the same scope;
  • +
  • The new variable name should not shadow any of the existing variables in the outer scopes, or be shadowed by any + of existing variables in the inner scopes, i.e., renaming to the new name should not change the semantics of the + program.
  • +

    +

    Usage: to apply this refactoring, point the cursor to any occurrence of this variable, then select + Rename Variable Name from Refactor , after that, Wrangler will prompt + to enter the new variable name in the mini-buffer. +

    + +

    similar_code_detection/6

    +
    +

    similar_code_detection(DirFileList::[filename() | dir()], MinLen::string(), MinFreq::string(), MinScore::string(), SearchPaths::[dir()], TabWidth::integer()) -> {ok, string()}

    +

    A similar code detector that searches for similar code across multiple Erlang modules. +

    This function reports similar expression sequences found in the directories specified, but does not + remove those clones though. The algorithm is based on the notion of anti-unification, or the least common generalisation. + The user needs to provide three parameters to be used by the clone detector, and + they are: the minimum length of an expression sequence, the minimum number of duplication times, and + a similarity score which should be between 0.1 and 1.0. +

    +

    + Usage: select Detect Similar Code in Dirs from Similar Code Detection, Wrangler will then prompt to + input the parameters needed. +

    + +

    similar_code_detection_in_buffer/6

    +
    +

    similar_code_detection_in_buffer(FileName::filename(), MinLen::string(), MinFreq::string(), MinScore::string(), SearchPaths::[dir()], TabWidth::integer()) -> {ok, string()}

    +

    A similar code detector that searches for similar code in the current Erlang buffer. +

    This function reports similar expression sequences found in the current Erlang buffer, but does not + remove those clones though. The user needs to provide three parameters to be used by the clone detector, and + they are: the minimum length of an expression sequence, the minimum number of duplication times, and + a similarity score which should be between 0.1 and 1.0. +

    +

    + Usage: select Detect Similar Code in Buffer from Similar Code Detection, Wrangler will then prompt to + input the parameters needed. +

    + +

    similar_expression_search_in_buffer/6

    +
    +

    similar_expression_search_in_buffer(FileName::filename(), Start::[integer()], End::[integer()], SimiScore::string(), SearchPaths::[dir()], TabWidth::integer()) -> {ok, [{filename(), {{integer(), integer()}, {integer(), integer()}}}]}

    +

    Search expression search in the current Erlang buffer. +

    This functionality allows searching for expression sequence that are similar to the expression sequence selected. In this context, + two expressions, A and B say, are similar if there exists an anti-unifier, say C, of A and B, and C satisfies the similarity score specified + by the user (the calculation calculated of similarity score is going to be further explored). +

    + Usage: highlight the expression sequence of interest, then selected Similar Expression Search in Current Buffer + from Similar Code Detection .

    + +

    similar_expression_search_in_dirs/6

    +
    +

    similar_expression_search_in_dirs(FileName::filename(), Start::[integer()], End::[integer()], SimiScore::string(), SearchPaths::[dir()], TabWidth::integer()) -> {ok, [{filename(), {{integer(), integer()}, {integer(), integer()}}}]}

    +

    Simiar expression search across multiple Erlang modules. +

    This functionality allows searching for expression sequence that are similar to the expression sequence selected. In this context, + two expressions, A and B say, are similar if there exists an anti-unifier, say C, of A and B, and C satisfies the similarity score specified + by the user (the calculation calculated of similarity score is going to be further explored). +

    + Usage: highlight the expression sequence of interest, then selected Similar Expression Search in Dirs from Simiar Code Detection.

    + +

    tuple_funpar/6

    +
    +

    tuple_funpar(FileName::filename(), StartLoc::[integer()], EndLoc::[integer()], SearchPaths::[dir()], Context::context(), TabWidth::integer()) -> {error, string()} | {ok, [filename()]}

    +

    Group a consecutive sequence of parameters of a function into a tuple. +

    + When the function under consideration is exported by the module where it is defined, this refactoring has a global effect. +

    +

    Suppose the new function after refactoring is f/n, then the following side-conditions apply: +

  • f/n should not cause confliction with any of the functions which are in scope in the + current module;
  • +
  • In the case that the function is imported by another module, then f/n + should not be already in scope (either defined or imported) in that module.
  • +

    +

    Usage: to apply this refactoring, highlight the arguments to be grouped into a tuple from + the function definition, then select Tuple Function Arguments from Refactor. +

    + +

    unfold_fun_app/5

    +
    +

    unfold_fun_app(FileName::filename(), Pos::[integer()], SearchPaths::[dir()], Context::context(), TabWidth::integer) -> {error, string()} | {ok, [string()]}

    +

    Unfold a function application to an instance of the function's body. +

    This refactoring replaces a function application with an instance of the function body. + With the current implementation, Wrangler unfolds a function application only if the function + is defined in the same module, and Wrangler could work out which function clause to use (in case + the function definition contains multiple function clauses). +

    +

    + Usage: Point the cursor to the function name in the function application to unfold, then + select Unfold Function Application from Refactor. +

    +
    + + +

    Generated by EDoc, Nov 5 2015, 16:30:21.

    + +