Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show argument names in function traces #162

Open
andytill opened this issue Feb 1, 2018 · 3 comments
Open

Show argument names in function traces #162

andytill opened this issue Feb 1, 2018 · 3 comments

Comments

@andytill
Copy link
Owner

andytill commented Feb 1, 2018

Erlyberly could show the names of function arguments above the values for function arguments in the term tree. Below is a screenshot of annotated records, it might look similar to this.

image

Module AST is already parsed for record metadata. Finding function argument names would be an expansion of that.

https://github.com/andytill/erlyberly/blob/master/src/main/resources/erlyberly/beam/erlyberly.erl#L172

For example, given the function in lists.

-spec sublist(List1, Start, Len) -> List2 when
      List1 :: [T],
      List2 :: [T],
      Start :: pos_integer(),
      Len :: non_neg_integer(),
      T :: term().

sublist(List, S, L) when is_integer(L), L >= 0 ->

The function may return something like.

{lists, [{sublist,["List","S","L"],...}]}

The dialyzer spec can be used but it may not exist. Functions can have multiple clauses. A binding name should be accepted over _ or a literal e.g. Index is more useful than 0 both of which may be present in different function clauses. There are many variations in function clauses, the AST parser should attempt to return something useful but could return a blank if the argument was too complex or long.

If anyone wants to attempt this, post a comment. I can help with the UI for anyone that doesn't want to code java! :D

@olafura
Copy link

olafura commented Feb 12, 2018

So I have an initial results, I have yet to convert the params from their ast form. But in their lies the crux, we have complex params like process_info2 on line 79, size_to_bytes on line 118 and record fields on line 155.

Here is a diff:

diff --git a/src/main/resources/erlyberly/beam/erlyberly.erl b/src/main/resources/erlyberly/beam/erlyberly.erl
index 633d35c..bb9a4b0 100644
--- a/src/main/resources/erlyberly/beam/erlyberly.erl
+++ b/src/main/resources/erlyberly/beam/erlyberly.erl
@@ -26,6 +26,7 @@
 -export([get_source_code/1]).
 -export([load_modules_on_path/1]).
 -export([load_module_records/1]).
+-export([load_module_functions/1]).
 -export([module_functions/0]).
 -export([process_info/0]).
 -export([saleyn_fun_src/1]).
@@ -174,6 +175,13 @@ load_module_records(Mod) ->
     Records = [{Tag, record_fields(Fields)} || {attribute,_,record,{Tag,Fields}} <- Forms],
     {ok, Records}.
 
+load_module_functions(Mod) ->
+    {ok, Forms} = load_module_forms(Mod),
+    Functions = [
+     {Function,Params} || {function,_,Function,_,FunctionBody} <- Forms,
+                          {clause,_,Params, _Guard, _Body} <- FunctionBody],
+    {ok, Functions}.
+
 %%% ============================================================================
 %%% module function tree
 %%% ============================================================================

@olafura
Copy link

olafura commented Feb 12, 2018

I can of course just extract the vars, if you want ;)

@andytill
Copy link
Owner Author

Thanks @olafura! Yes the return should be a flat list of binding names, it is very difficult to take this apart in Java, like an untyped XML DOM. The function clause combinations do get very complex. In the example case we can get the binding names from the dialyzer spec initially, and then use the function clause to fill in the blanks.

So for example, in this function.

myfunc(0, Acc) -> Acc
myfunc(Index, _) -> myfunc(Index-1, 2).

The list of returned arguments should be ["Index", "Acc"]. If there were two different names for the same argument e.g.

myfunc(0, Acc) -> Acc
myfunc(Index, X) -> myfunc(Index-1, X+1).

Then we could return ["Index", "Acc|X"]. Names in the dialyzer spec should probably override this, unless we don't trust that the spec is being kept upto date!? Maybe we should return that too if it is different to the names in the clause.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants