-
-
Save manpages/3069849 to your computer and use it in GitHub Desktop.
Parse out Mod, Func, Name from function type spec
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% Consider | |
%% mod:func([A],{A,B},list(), any(), some_type({A,list(),B})) -> ok | error. | |
%% | |
%% Start from the beginning. Scan each character | |
%% | |
%% 1. Once we hit ":", we've got our module name, start looking for function | |
%% name. | |
%% 2. Once we hit "(", we've got our method name, start looking for arguments | |
%% 3. Arguments are a bit trickier | |
%% 3.1 If we encounter a "{", "[", "(" we don't care about anything | |
%% until we hit a matching closing paranthesis/bracket. Every time | |
%% we hit an opening paranthesis/bracket, we increase depth level. | |
%% Once we hit a closing p/b, we decrease depth level | |
%% We only care about arguments on level 0 | |
%% 3.2 Arguments are spearated by commas. If we hit a comma on depth 0, | |
%% we increment the counter | |
%% 3.3 Once we hit a ")" on depth 0 | |
%% 3.3.1 If there were no characters between thhe opening paranthesis and | |
%% this one, we return 0 | |
%% Example: mod:func() | |
%% 3.3.2 If there were characters, we increase our counter by one and return | |
%% it | |
%% Example: mod:func(a) %% 0 commas, 1 argument | |
%% Example: mod:func(a, b) %% 1 comma, 2 arguments | |
%% 4. Discard the rest of the string, return {Mod, Func, Arity} | |
%% | |
-module(mo). | |
-export([parse/1, test/0]). | |
%% Bullet point 1. | |
parse(String) -> | |
parse_module(lists:flatten(String), []). | |
parse_module([$:|T], Acc) -> | |
Mod = lists:reverse(Acc), | |
{Func, Arity, Rest} = case parse_func(T) of | |
{[], A, R} -> {[], A, R}; | |
{ F, A, R} -> {list_to_atom(F), A, R} | |
end, | |
{list_to_atom(Mod), Func, Arity, Rest}; | |
parse_module([$(|T], Acc) -> | |
{Func, Arity, Rest} = case parse_func([$(|T], Acc) of | |
{[], A, R} -> {[], A, R}; | |
{ F, A, R} -> {list_to_atom(F), A, R} | |
end, | |
{[], Func, Arity, Rest}; | |
parse_module([H|T], Acc) -> | |
parse_module(T, [H | Acc]). | |
%% Bullet point 2. | |
parse_func(L) -> | |
parse_func(L, []). | |
parse_func([$(|T] = Rest, Acc) -> | |
Func = lists:reverse(Acc), | |
Arity = parse_arity(T), | |
{Func, Arity, Rest}; | |
parse_func([H|T], Acc) -> | |
parse_func(T, [H | Acc]). | |
%% Bullet point 3. | |
parse_arity(L) -> | |
parse_arity(L, 0, 0, 0). | |
parse_arity([$)|_], Acc, 0=_Chars, 0=_Depth) -> Acc; | |
parse_arity([$)|_], Acc, _Chars, 0=_Depth) -> Acc + 1; | |
parse_arity([$,|T], Acc, Chars, 0 = Depth) -> | |
parse_arity(T, Acc + 1, Chars + 1, Depth); | |
parse_arity([Char|T], Acc, Chars, Depth) -> | |
parse_arity(T, Acc, Chars+1, maybe_change_depth(Depth, Char)). | |
maybe_change_depth(Depth, Char) when Char =:= $) | |
orelse Char =:= $] | |
orelse Char =:= $} -> | |
Depth - 1; | |
maybe_change_depth(Depth, Char) when Char =:= $( | |
orelse Char =:= $[ | |
orelse Char =:= ${ -> | |
Depth + 1; | |
maybe_change_depth(Depth, _) -> | |
Depth. | |
%%============================================================================= | |
test() -> | |
{mod, func, 0, _} = parse("mod:func()"), | |
{mod, func, 1, _} = parse("mod:func(a)"), | |
{mod, func, 5, _} = | |
parse([ "mod:func([A],{A,B},list(), any(), some_type({A,list(),B})) -> " | |
, "ok | error."]), | |
{mod, func, 2, _} = parse("mod:func(A, type()) when A::list() -> ok | error."), | |
ok. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment