-
Notifications
You must be signed in to change notification settings - Fork 145
[#235] Single pass over forms #261
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,46 +25,47 @@ parse(Text) -> | |
|
|
||
| -spec parse_file(file:io_device()) -> {ok, [poi()]}. | ||
| parse_file(IoDevice) -> | ||
| {ok, Forms} = els_dodger:parse(IoDevice, {1, 1}), | ||
| Tree = erl_syntax:form_list(Forms), | ||
| %% Reset file pointer position. | ||
| {ok, 0} = file:position(IoDevice, 0), | ||
| {ok, Extra} = parse_attribute_pois(IoDevice, [], {1, 1}), | ||
| {ok, NestedPOIs} = els_dodger:parse(IoDevice, {1, 1}, fun parse_form/3, []), | ||
| ok = file:close(IoDevice), | ||
| POIs = points_of_interest(Tree), | ||
| {ok, Extra ++ POIs}. | ||
| {ok, lists:flatten(NestedPOIs)}. | ||
|
|
||
| %%============================================================================== | ||
| %% Internal Functions | ||
| %%============================================================================== | ||
| -spec parse_form(file:io_device(), any(), [any()]) -> | ||
| {'ok', erl_syntax:forms() | ||
| | none, integer()} | ||
| | {'eof', integer()} | ||
| | {'error', any(), integer()}. | ||
| parse_form(Dev, L0, Options) -> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems a re-implementation of
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I was misreading the code. Ignore this comment.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An alternative option would have been to add a callback function to the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would have required a change in the implementation of dodger which I was trying to avoid. |
||
| parse_form(Dev, L0, fun els_dodger:normal_parser/2, Options). | ||
|
|
||
| -spec parse_attribute_pois(io:device(), [poi()], erl_anno:location()) -> | ||
| {ok, [poi()]} | {error, any()}. | ||
| parse_attribute_pois(IoDevice, Acc, StartLoc) -> | ||
| case io:scan_erl_form(IoDevice, "", StartLoc) of | ||
| {ok, Tokens, EndLoc} -> | ||
| case erl_parse:parse_form(Tokens) of | ||
| {ok, Form} -> | ||
| POIs = find_attribute_pois(Form, Tokens), | ||
| parse_attribute_pois(IoDevice, POIs ++ Acc, EndLoc); | ||
| {error, _Error} -> | ||
| parse_attribute_pois(IoDevice, Acc, EndLoc) | ||
| -spec parse_form(file:io_device(), any(), function(), [any()]) -> | ||
| {'ok', erl_syntax:forms() | none, integer()} | ||
| | {'eof', integer()} | ||
| | {'error', any(), integer()}. | ||
| parse_form(Dev, L0, Parser, _Options) -> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we please use the original naming for the variables? E.g. |
||
| case io:scan_erl_form(Dev, "", L0) of | ||
| {ok, Ts, L1} -> | ||
| case catch {ok, Parser(Ts, undefined)} of | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't use the deprecated |
||
| {ok, F} -> | ||
| POIs = [find_attribute_pois(F, Ts), points_of_interest(F)], | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that we have the single pass, it probably makes more sense to check here whether we are dealing with an attribute and execute the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The check is done in the function itself, adding it here would only make this function harder to read and would bring no benefit IMO. |
||
| {ok, POIs, L1}; | ||
| _ -> | ||
| {ok, [], L1} | ||
| end; | ||
| {eof, _} -> | ||
| {ok, Acc}; | ||
| {error, ErrorInfo, EndLoc} -> | ||
| lager:warning( "Could not parse extra information [end_loc=p] ~p" | ||
| , [EndLoc, ErrorInfo] | ||
| ), | ||
| {ok, Acc} | ||
| {error, _IoErr, _L1} = Err -> Err; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Considering we are pattern matching on
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The result from this function is processed by the code in |
||
| {error, _Reason} -> {eof, L0}; % This is probably encoding problem | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know the (missing an article) comment comes from the dodger, but I would get rid of it and, instead, add a comment to the top of this function explaining this is a simplified version of the respective dodger function. |
||
| {eof, _L1} = Eof -> Eof | ||
| end. | ||
|
|
||
| %%============================================================================== | ||
| %% Internal Functions | ||
| %%============================================================================== | ||
|
|
||
| -spec find_attribute_pois(erl_parse:abstract_form(), [erl_scan:token()]) -> | ||
| [poi()]. | ||
| find_attribute_pois(Form, Tokens) -> | ||
| case erl_syntax:type(Form) of | ||
| attribute -> | ||
| case erl_syntax_lib:analyze_attribute(Form) of | ||
| case catch erl_syntax_lib:analyze_attribute(Form) of | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. Please don't use the old-style |
||
| {export, Exports} -> | ||
| %% The first atom is the attribute name, so we skip it. | ||
| [_|Atoms] = [T|| {atom, _, _} = T <- Tokens], | ||
|
|
@@ -114,11 +115,8 @@ do_find_spec_points_of_interest(Tree, Acc) -> | |
|
|
||
| -spec points_of_interest(tree()) -> [poi()]. | ||
| points_of_interest(Tree) -> | ||
| lists:flatten( | ||
| erl_syntax_lib:fold( | ||
| fun(T, Acc) -> | ||
| [do_points_of_interest(T)|Acc] | ||
| end, [], Tree)). | ||
| FoldFun = fun(T, Acc) -> do_points_of_interest(T) ++ Acc end, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean at the end as in |
||
| erl_syntax_lib:fold(FoldFun, [], Tree). | ||
|
|
||
| %% @edoc Return the list of points of interest for a given `Tree`. | ||
| -spec do_points_of_interest(tree()) -> [poi()]. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to bring in the upstream version, if possible.
What are the included changes?
Are you pull-requesting them to upstream?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the PR with all the improvements.