diff options
Diffstat (limited to 'lib/diameter/src/compiler/diameter_spec_scan.erl')
-rw-r--r-- | lib/diameter/src/compiler/diameter_spec_scan.erl | 157 |
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. |