Permalink
Browse files

rewritten yecc and leex parser

  • Loading branch information...
1 parent 5cafc0c commit dfce329e264bc770019ba2aeae9dccab704b7c31 @freke freke committed Feb 5, 2011
View
@@ -25,6 +25,7 @@
%%
%% @doc A protcol buffers encoding and decoding module.
-module(protobuffs).
+
%% Pubic
-export([encode/3, encode_packed/3, decode/2, decode_packed/2]).
@@ -43,15 +44,35 @@
-define(TYPE_END_GROUP, 4).
-define(TYPE_32BIT, 5).
-%% @spec encode(FieldID, Value, Type) -> Result
-%% FieldID = integer()
-%% Value = any()
-%% Type = bool | enum | int32 | uint32 | int64 | unit64 | sint32 | sint64 | fixed32 | sfixed32 | fixed64 | sfixed64 | string | bytes | float | double
-%% Result = list()
+-type encoded_field_type() ::
+ ?TYPE_VARINT | ?TYPE_64BIT | ?TYPE_STRING |
+ ?TYPE_START_GROUP | ?TYPE_END_GROUP | ?TYPE_32BIT.
+
+-type field_type() :: bool | enum | int32 | uint32 | int64 |
+ unit64 | sint32 | sint64 | fixed32 |
+ sfixed32 | fixed64 | sfixed64 | string |
+ bytes | float | double.
+
+%%--------------------------------------------------------------------
%% @doc Encode an Erlang data structure into a Protocol Buffers value.
+%% @end
+%%--------------------------------------------------------------------
+-spec encode(FieldID :: non_neg_integer(),
+ Value :: any(),
+ Type :: field_type()) ->
+ binary().
+
encode(FieldID, Value, Type) ->
iolist_to_binary(encode_internal(FieldID, Value, Type)).
+%%--------------------------------------------------------------------
+%% @doc Encode an list of Erlang data structure into a Protocol Buffers values.
+%% @end
+%%--------------------------------------------------------------------
+-spec encode_packed(FieldID :: non_neg_integer(),
+ Values :: list(),
+ Type :: field_type()) ->
+ binary().
encode_packed(_FieldID, [], _Type) ->
<<>>;
encode_packed(FieldID, Values, Type) ->
@@ -60,6 +81,10 @@ encode_packed(FieldID, Values, Type) ->
iolist_to_binary([encode_field_tag(FieldID, ?TYPE_STRING),Size,PackedValues]).
%% @hidden
+-spec encode_internal(FieldID :: non_neg_integer(),
+ Value :: any(),
+ Type :: field_type()) ->
+ iolist().
encode_internal(FieldID, false, bool) ->
encode_internal(FieldID, 0, int32);
encode_internal(FieldID, true, bool) ->
@@ -126,58 +151,68 @@ encode_internal(FieldID, '-infinity', double) ->
[encode_field_tag(FieldID, ?TYPE_64BIT), <<0:48,16#F0,16#FF>>].
-
-
%% @hidden
+-spec encode_packed_internal(Values :: list(),
+ ExpectedType :: field_type(),
+ Acc :: list()) ->
+ iolist().
encode_packed_internal([],_Type,Acc) ->
lists:reverse(Acc);
-encode_packed_internal([Integer|Tail], ExpectedType, Acc) ->
- [_|Value] = encode_internal(1, Integer, ExpectedType),
- encode_packed_internal(Tail, ExpectedType, [Value|Acc]).
+encode_packed_internal([Value|Tail], ExpectedType, Acc) ->
+ [_|V] = encode_internal(1, Value, ExpectedType),
+ encode_packed_internal(Tail, ExpectedType, [V|Acc]).
%%--------------------------------------------------------------------
%% @doc Will be hidden in future releases
-%% @spec read_field_num_and_wire_type(Bytes) -> {{FieldID, WireType}, Rest}
-%% Bytes = binary()
-%% FieldID = integer()
-%% WireType = atom()
-%% Rest = binary()
%% @end
%%--------------------------------------------------------------------
+-spec read_field_num_and_wire_type(Bytes :: binary()) ->
+ {{non_neg_integer(), encoded_field_type()}, binary()}.
read_field_num_and_wire_type(Bytes) ->
{Tag, Rest} = decode_varint(Bytes),
FieldID = Tag bsr 3,
WireType = Tag band 7,
{{FieldID, WireType}, Rest}.
-%% @spec decode(Bytes, ExpectedType) -> Result
-%% Bytes = binary()
-%% ExpectedType = bool | enum | int32 | uint32 | int64 | unit64 | sint32 | sint64 | fixed32 | sfixed32 | fixed64 | sfixed64 | string | bytes | float | double
-%% Result = {{integer(), any()}, binary()}
+%%--------------------------------------------------------------------
+%% @doc Decode a singel value from a protobuffs data structure
+%% @end
+%%--------------------------------------------------------------------
+-spec decode(Bytes :: binary(), ExpectedType :: field_type()) ->
+ {{non_neg_integer(), any()}, binary()}.
decode(Bytes, ExpectedType) ->
{{FieldID, WireType}, Rest} = read_field_num_and_wire_type(Bytes),
{Value, Rest1} = decode_value(Rest, WireType, ExpectedType),
{{FieldID, Value}, Rest1}.
-%% @spec decode_packed(Bytes, ExpectedType) -> Result
-%% Bytes = binary()
-%% ExpectedType = bool | enum | int32 | uint32 | int64 | unit64 | sint32 | sint64 | float | double
-%% Result = {{integer(), any()}, binary()}
+%%--------------------------------------------------------------------
+%% @doc Decode packed values from a protobuffs data structure
+%% @end
+%%--------------------------------------------------------------------
+-spec decode_packed(Bytes :: binary(), ExpectedType :: field_type()) ->
+ {{non_neg_integer(), any()}, binary()}.
decode_packed(Bytes, ExpectedType) ->
{{FieldID, ?TYPE_STRING}, Rest} = read_field_num_and_wire_type(Bytes),
{Length, Rest1} = decode_varint(Rest),
{Packed,Rest2} = split_binary(Rest1, Length),
Values = decode_packed_values(Packed, ExpectedType, []),
{{FieldID, Values},Rest2}.
-%% @spec next_field_num(Bytes) -> Result
-%% Bytes = binary()
-%% Result = {integer(),integer()}
+%%--------------------------------------------------------------------
+%% @doc Returns the next field number id from a protobuffs data structure
+%% @end
+%%--------------------------------------------------------------------
+-spec next_field_num(Bytes :: binary()) ->
+ {ok,non_neg_integer()}.
next_field_num(Bytes) ->
{{FieldID,_WiredType}, _Rest} = read_field_num_and_wire_type(Bytes),
{ok,FieldID}.
%% @hidden
+-spec decode_packed_values(Bytes :: binary(),
+ Type :: field_type(),
+ Acc :: list()) ->
+ iolist().
decode_packed_values(<<>>, _, Acc) ->
lists:reverse(Acc);
decode_packed_values(Bytes, bool, Acc) ->
@@ -214,14 +249,12 @@ decode_packed_values(Bytes, double, Acc) ->
%%--------------------------------------------------------------------
%% @doc Will be hidden in future releases
-%% @spec decode_value(Bytes, Type, ExpectedType) -> {Value, Rest}
-%% Bytes = binary()
-%% Type = atom()
-%% ExpectedType = atom()
-%% Value = value of Type
-%% Rest = binary()
%% @end
%%--------------------------------------------------------------------
+-spec decode_value(Bytes :: binary(),
+ WireType :: encoded_field_type(),
+ ExpectedType :: field_type()) ->
+ {any(),binary()}.
decode_value(Bytes, ?TYPE_VARINT, ExpectedType) ->
{Value, Rest} = decode_varint(Bytes),
{typecast(Value, ExpectedType), Rest};
@@ -264,6 +297,8 @@ decode_value(Value, WireType, ExpectedType) ->
exit({error, {unexpected_value, WireType, ExpectedType, Value}}).
%% @hidden
+-spec typecast(Value :: any(), Type :: field_type()) ->
+ any().
typecast(Value, SignedType) when SignedType =:= int32; SignedType =:= int64 ->
if
Value band 16#8000000000000000 =/= 0 -> Value - 16#10000000000000000;
@@ -277,18 +312,28 @@ typecast(Value, _) ->
Value.
%% @hidden
+-spec encode_field_tag(FieldID :: non_neg_integer(),
+ FieldType :: encoded_field_type()) ->
+ binary().
encode_field_tag(FieldID, FieldType) when FieldID band 16#3fffffff =:= FieldID ->
encode_varint((FieldID bsl 3) bor FieldType).
%% @hidden
+-spec encode_varint_field(FieldID :: non_neg_integer(),
+ Integer :: integer()) ->
+ iolist().
encode_varint_field(FieldID, Integer) ->
[encode_field_tag(FieldID, ?TYPE_VARINT), encode_varint(Integer)].
%% @hidden
+-spec encode_varint(I :: integer()) ->
+ binary().
encode_varint(I) ->
encode_varint(I, []).
%% @hidden
+-spec encode_varint(I :: integer(), Acc :: list()) ->
+ binary().
encode_varint(I, Acc) when I =< 16#7f ->
iolist_to_binary(lists:reverse([I | Acc]));
encode_varint(I, Acc) ->
@@ -298,8 +343,13 @@ encode_varint(I, Acc) ->
encode_varint(First_X_Bits, [With_Leading_Bit|Acc]).
%% @hidden
+-spec decode_varint(Bytes :: binary()) ->
+ {integer(), binary()}.
decode_varint(Bytes) ->
decode_varint(Bytes, []).
+
+-spec decode_varint(Bytes :: binary(), list()) ->
+ {integer(), binary()}.
decode_varint(<<0:1, I:7, Rest/binary>>, Acc) ->
Acc1 = [I|Acc],
Result =
View
@@ -27,11 +27,9 @@
%%--------------------------------------------------------------------
%% @doc Generats a built .beam file and header file .hrl
-%% @spec scan_file(ProtoFile) -> Result
-%% ProtoFile = string()
-%% Result = ok | {error, Reason}
-%% Reason = ext_posix() | terminated | system_limit
%%--------------------------------------------------------------------
+-spec scan_file(ProtoFile :: string()) ->
+ ok | {error, _}.
scan_file(ProtoFile) ->
scan_file(ProtoFile,[]).
@@ -40,12 +38,9 @@ scan_file(ProtoFile) ->
%% Considerd option properties: output_include_dir,
%% output_ebin_dir,
%% imports_dir
-%% @spec scan_file(ProtoFile,Options) -> Result
-%% ProtoFile = string()
-%% Options = proplists()
-%% Result = ok | {error, Reason}
-%% Reason = ext_posix() | terminated | system_limit
%%--------------------------------------------------------------------
+-spec scan_file(ProtoFile :: string(), Options :: list()) ->
+ ok | {error, _}.
scan_file(ProtoFile,Options) when is_list(ProtoFile) ->
Basename = filename:basename(ProtoFile, ".proto") ++ "_pb",
{ok,FirstParsed} = parse(ProtoFile),
@@ -57,11 +52,9 @@ scan_file(ProtoFile,Options) when is_list(ProtoFile) ->
%%--------------------------------------------------------------------
%% @doc Generats a source .erl file and header file .hrl
-%% @spec generate_source(ProtoFile) -> Result
-%% ProtoFile = string()
-%% Result = ok | {error, Reason}
-%% Reason = ext_posix() | terminated | system_limit
%%--------------------------------------------------------------------
+-spec generate_source(ProtoFile :: string()) ->
+ ok | {error, _}.
generate_source(ProtoFile) ->
generate_source(ProtoFile,[]).
@@ -70,12 +63,9 @@ generate_source(ProtoFile) ->
%% Consider option properties: output_include_dir,
%% output_src_dir,
%% imports_dir
-%% @spec generate_source(ProtoFile,Options) -> Result
-%% ProtoFile = string()
-%% Options = proplists()
-%% Result = ok | {error, Reason}
-%% Reason = ext_posix() | terminated | system_limit
%%--------------------------------------------------------------------
+-spec generate_source(ProtoFile :: string(), Options :: list()) ->
+ ok | {error, atom() | badarg | terminated | system_limit}.
generate_source(ProtoFile,Options) when is_list (ProtoFile) ->
Basename = filename:basename(ProtoFile, ".proto") ++ "_pb",
{ok,FirstParsed} = parse(ProtoFile),
@@ -358,12 +348,12 @@ collect_full_messages([{enum, Name, Fields} | Tail], AccEnum, AccMsg) ->
end,
FieldsOut = lists:foldl(
- fun (Input, TmpAcc) ->
- case Input of
- {enum, IntValue, EnumAtom} -> [{enum,
- type_path_to_type(ListName),
- IntValue,
- list_to_atom(EnumAtom)} | TmpAcc];
+ fun (Field, TmpAcc) ->
+ case Field of
+ {EnumAtom, IntValue} -> [{enum,
+ type_path_to_type(ListName),
+ IntValue,
+ EnumAtom} | TmpAcc];
_ -> TmpAcc
end
end, [], Fields),
Oops, something went wrong.

0 comments on commit dfce329

Please sign in to comment.