Skip to content

Commit

Permalink
rewritten yecc and leex parser
Browse files Browse the repository at this point in the history
  • Loading branch information
freke committed Feb 5, 2011
1 parent 5cafc0c commit dfce329
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 148 deletions.
114 changes: 82 additions & 32 deletions src/protobuffs.erl
Expand Up @@ -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]).

Expand All @@ -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) ->
Expand All @@ -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) ->
Expand Down Expand Up @@ -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) ->
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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;
Expand All @@ -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) ->
Expand All @@ -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 =
Expand Down
38 changes: 14 additions & 24 deletions src/protobuffs_compile.erl
Expand Up @@ -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,[]).

Expand All @@ -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),
Expand All @@ -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,[]).

Expand All @@ -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),
Expand Down Expand Up @@ -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),
Expand Down

0 comments on commit dfce329

Please sign in to comment.