aboutsummaryrefslogtreecommitdiffstats
path: root/lib/diameter/src/compiler/diameter_spec_scan.erl
diff options
context:
space:
mode:
authorAnders Svensson <[email protected]>2011-05-18 18:29:12 +0200
committerAnders Svensson <[email protected]>2011-05-18 18:29:12 +0200
commit3c15ff32e89e401b4dde2b8acc9699be2614b996 (patch)
tree184dc988fb2ab3af04a532bc59cc794a8d74fbd3 /lib/diameter/src/compiler/diameter_spec_scan.erl
parentb1e768e86593178810c8a0b3c38443dcf6be5181 (diff)
downloadotp-3c15ff32e89e401b4dde2b8acc9699be2614b996.tar.gz
otp-3c15ff32e89e401b4dde2b8acc9699be2614b996.tar.bz2
otp-3c15ff32e89e401b4dde2b8acc9699be2614b996.zip
Initial commit of the diameter application.
The application provides an implementation of the Diameter protocol as defined in RFC 3588.
Diffstat (limited to 'lib/diameter/src/compiler/diameter_spec_scan.erl')
-rw-r--r--lib/diameter/src/compiler/diameter_spec_scan.erl157
1 files changed, 157 insertions, 0 deletions
diff --git a/lib/diameter/src/compiler/diameter_spec_scan.erl b/lib/diameter/src/compiler/diameter_spec_scan.erl
new file mode 100644
index 0000000000..bc0448882a
--- /dev/null
+++ b/lib/diameter/src/compiler/diameter_spec_scan.erl
@@ -0,0 +1,157 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(diameter_spec_scan).
+
+%%
+%% Functions used by the spec file parser in diameter_spec_util.
+%%
+
+-export([split/1,
+ split/2,
+ parse/1]).
+
+%%% -----------------------------------------------------------
+%%% # parse/1
+%%%
+%%% Output: list of Token
+%%%
+%%% Token = '{' | '}' | '<' | '>' | '[' | ']'
+%%% | '*' | '::=' | ':' | ',' | '-'
+%%% | {name, string()}
+%%% | {tag, atom()}
+%%% | {number, integer() >= 0}
+%%%
+%%% Tokenize a string. Fails if the string does not parse.
+%%% -----------------------------------------------------------
+
+parse(S) ->
+ parse(S, []).
+
+%% parse/2
+
+parse(S, Acc) ->
+ acc(split(S), Acc).
+
+acc({T, Rest}, Acc) ->
+ parse(Rest, [T | Acc]);
+acc("", Acc) ->
+ lists:reverse(Acc).
+
+%%% -----------------------------------------------------------
+%%% # split/2
+%%%
+%%% Output: {list() of Token, Rest}
+%%%
+%%% Extract a specified number of tokens from a string. Returns a list
+%%% of length less than the specified number if there are less than
+%%% this number of tokens to be parsed.
+%%% -----------------------------------------------------------
+
+split(Str, N)
+ when N >= 0 ->
+ split(N, Str, []).
+
+split(0, Str, Acc) ->
+ {lists:reverse(Acc), Str};
+
+split(N, Str, Acc) ->
+ case split(Str) of
+ {T, Rest} ->
+ split(N-1, Rest, [T|Acc]);
+ "" = Rest ->
+ {lists:reverse(Acc), Rest}
+ end.
+
+%%% -----------------------------------------------------------
+%%% # split/1
+%%%
+%%% Output: {Token, Rest} | ""
+%%%
+%%% Extract the next token from a string.
+%%% -----------------------------------------------------------
+
+split("" = Rest) ->
+ Rest;
+
+split("::=" ++ T) ->
+ {'::=', T};
+
+split([H|T])
+ when H == ${; H == $};
+ H == $<; H == $>;
+ H == $[; H == $];
+ H == $*; H == $:; H == $,; H == $- ->
+ {list_to_atom([H]), T};
+
+split([H|T]) when $A =< H, H =< $Z;
+ $0 =< H, H =< $9 ->
+ {P, Rest} = splitwith(fun is_name_ch/1, [H], T),
+ Tok = try
+ {number, read_int(P)}
+ catch
+ error:_ ->
+ {name, P}
+ end,
+ {Tok, Rest};
+
+split([H|T]) when $a =< H, H =< $z ->
+ {P, Rest} = splitwith(fun is_name_ch/1, [H], T),
+ {{tag, list_to_atom(P)}, Rest};
+
+split([H|T]) when H == $\t;
+ H == $\s;
+ H == $\n ->
+ split(T).
+
+%% read_int/1
+
+read_int([$0,X|S])
+ when X == $X;
+ X == $x ->
+ {ok, [N], []} = io_lib:fread("~16u", S),
+ N;
+
+read_int(S) ->
+ list_to_integer(S).
+
+%% splitwith/3
+
+splitwith(Fun, Acc, S) ->
+ split([] /= S andalso Fun(hd(S)), Fun, Acc, S).
+
+split(true, Fun, Acc, [H|T]) ->
+ splitwith(Fun, [H|Acc], T);
+split(false, _, Acc, S) ->
+ {lists:reverse(Acc), S}.
+
+is_name_ch(C) ->
+ is_alphanum(C) orelse C == $- orelse C == $_.
+
+is_alphanum(C) ->
+ is_lower(C) orelse is_upper(C) orelse is_digit(C).
+
+is_lower(C) ->
+ $a =< C andalso C =< $z.
+
+is_upper(C) ->
+ $A =< C andalso C =< $Z.
+
+is_digit(C) ->
+ $0 =< C andalso C =< $9.