xtool/contrib/fundamentals/ProtocolBuffers/flcProtoBufProtoNodes.pas

1286 lines
35 KiB
ObjectPascal

{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcProtoBufProtoNodes.pas }
{ File version: 5.04 }
{ Description: Protocol Buffer proto file nodes. }
{ }
{ Copyright: Copyright (c) 2012-2016, David J Butler }
{ All rights reserved. }
{ This file is licensed under the BSD License. }
{ See http://www.opensource.org/licenses/bsd-license.php }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ Revision history: }
{ }
{ 2012/04/15 0.01 Initial development: Proto nodes. }
{ 2012/04/26 0.02 Resolve delimited identifiers. }
{ 2016/01/14 0.03 RawByteString changes. }
{ 2016/01/14 5.04 Revised for Fundamentals 5. }
{ }
{******************************************************************************}
{$INCLUDE flcProtoBuf.inc}
unit flcProtoBufProtoNodes;
interface
uses
{ System }
SysUtils,
{ Fundamentals }
flcUtils;
type
TpbProtoNodeFactory = class;
TpbProtoNode = class
protected
public
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; virtual;
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; virtual;
function ExpectResolvedValue(const AIdentifier: RawByteString): TpbProtoNode;
function ExpectResolvedType(const AIdentifier: RawByteString): TpbProtoNode;
function GetAsProtoString: RawByteString; virtual;
end;
EpbProtoNode = class(Exception);
TpbProtoEnum = class; // forward
TpbProtoEnumValue = class(TpbProtoNode)
protected
FParentEnum : TpbProtoEnum;
FName : RawByteString;
FValue : LongInt;
public
constructor Create(const AParentEnum: TpbProtoEnum);
property Name: RawByteString read FName write FName;
property Value: LongInt read FValue write FValue;
function GetAsProtoString: RawByteString; override;
end;
TpbProtoMessage = class; // forward
TpbProtoEnum = class(TpbProtoNode)
protected
FName : RawByteString;
FValues : array of TpbProtoEnumValue;
public
constructor Create(const AParentNode: TpbProtoNode);
property Name: RawByteString read FName write FName;
procedure Add(const V: TpbProtoEnumValue);
function GetValueCount: Integer;
function GetValue(const Idx: Integer): TpbProtoEnumValue;
function GetValueByName(const AName: RawByteString): TpbProtoEnumValue;
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
function GetAsProtoString: RawByteString; override;
end;
TpbProtoLiteralType = (
pltNone,
pltInteger,
pltFloat,
pltString,
pltBoolean,
pltIdentifier
);
TpbProtoLiteral = class(TpbProtoNode)
protected
FParentNode : TpbProtoNode;
FLiteralType : TpbProtoLiteralType;
FLiteralInt : Int64;
FLiteralFloat : Extended;
FLiteralStr : RawByteString;
FLiteralBool : Boolean;
FLiteralIden : RawByteString;
public
constructor Create(const AParentNode: TpbProtoNode);
property LiteralType: TpbProtoLiteralType read FLiteralType write FLiteralType;
property LiteralInt: Int64 read FLiteralInt write FLiteralInt;
property LiteralFloat: Extended read FLiteralFloat write FLiteralFloat;
property LiteralStr: RawByteString read FLiteralStr write FLiteralStr;
property LiteralBool: Boolean read FLiteralBool write FLiteralBool;
property LiteralIden: RawByteString read FLiteralIden write FLiteralIden;
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
function GetAsProtoString: RawByteString; override;
function LiteralIdenValue: TpbProtoNode;
end;
TpbProtoOption = class(TpbProtoNode)
protected
FCustom : Boolean;
FName : RawByteString;
FValue : TpbProtoLiteral;
procedure SetValue(const Value: TpbProtoLiteral);
public
constructor Create(const AFactory: TpbProtoNodeFactory);
destructor Destroy; override;
property Custom: Boolean read FCustom write FCustom;
property Name: RawByteString read FName write FName;
property Value: TpbProtoLiteral read FValue write FValue;
end;
TpbProtoFieldCardinality = (
pfcNone,
pfcRequired,
pfcOptional,
pfcRepeated
);
TpbProtoFieldBaseType = (
pftNone,
pftDouble,
pftFloat,
pftInt32,
pftInt64,
pftUInt32,
pftUInt64,
pftSInt32,
pftSInt64,
pftFixed32,
pftFixed64,
pftSFixed32,
pftSFixed64,
pftBool,
pftString,
pftBytes,
pftIdentifier
);
TpbProtoField = class; // forward
TpbProtoFieldType = class(TpbProtoNode)
protected
FParentField : TpbProtoField;
FBaseType : TpbProtoFieldBaseType;
FIdenStr : RawByteString;
public
constructor Create(const AParentField: TpbProtoField);
property ParentField: TpbProtoField read FParentField;
property BaseType: TpbProtoFieldBaseType read FBaseType write FBaseType;
property IdenStr: RawByteString read FIdenStr write FIdenStr;
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
function GetAsProtoString: RawByteString; override;
function IsSimpleType: Boolean;
function IsIdenType: Boolean;
function IdenType: TpbProtoNode;
end;
TpbProtoField = class(TpbProtoNode)
protected
FParentMessage : TpbProtoMessage;
FName : RawByteString;
FFieldType : TpbProtoFieldType;
FCardinality : TpbProtoFieldCardinality;
FTagID : LongInt;
FDefaultValue : TpbProtoLiteral;
FOptionPacked : Boolean;
FOptions : array of TpbProtoOption;
procedure SetFieldType(const Value: TpbProtoFieldType);
procedure SetDefaultValue(const Value: TpbProtoLiteral);
public
constructor Create(const AParentMessage: TpbProtoMessage; const AFactory: TpbProtoNodeFactory);
destructor Destroy; override;
property ParentMessage: TpbProtoMessage read FParentMessage;
property Name: RawByteString read FName write FName;
property FieldType: TpbProtoFieldType read FFieldType write SetFieldType;
property Cardinality: TpbProtoFieldCardinality read FCardinality write FCardinality;
property TagID: LongInt read FTagID write FTagID;
property DefaultValue: TpbProtoLiteral read FDefaultValue write SetDefaultValue;
property OptionPacked: Boolean read FOptionPacked write FOptionPacked;
procedure AddOption(const Option: TpbProtoOption);
function GetOptionCount: Integer;
function GetOption(const Idx: Integer): TpbProtoOption;
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
function GetAsProtoString: RawByteString; override;
end;
TpbProtoMessage = class(TpbProtoNode)
protected
FParentNode : TpbProtoNode;
FName : RawByteString;
FMessages : array of TpbProtoMessage;
FFields : array of TpbProtoField;
FEnums : array of TpbProtoEnum;
FExtensionsMin : LongInt;
FExtensionsMax : LongInt;
function GetFieldCount: Integer;
function GetField(const Idx: Integer): TpbProtoField;
function GetEnumCount: Integer;
function GetEnum(const Idx: Integer): TpbProtoEnum;
function GetEnumByName(const AName: RawByteString): TpbProtoEnum;
function GetMessageCount: Integer;
function GetMessage(const Idx: Integer): TpbProtoMessage;
function GetMessageByName(const AName: RawByteString): TpbProtoMessage;
public
constructor Create(const AParentNode: TpbProtoNode);
destructor Destroy; override;
property ParentNode: TpbProtoNode read FParentNode;
property Name: RawByteString read FName write FName;
procedure AddField(const F: TpbProtoField);
property FieldCount: Integer read GetFieldCount;
property Field[const Idx: Integer]: TpbProtoField read GetField;
function GetFieldByTagID(const ATagID: Integer): TpbProtoField;
procedure AddEnum(const E: TpbProtoEnum);
property EnumCount: Integer read GetEnumCount;
property Enum[const Idx: Integer]: TpbProtoEnum read GetEnum;
procedure AddMessage(const M: TpbProtoMessage);
property MessageCount: Integer read GetMessageCount;
property Msg[const Idx: Integer]: TpbProtoMessage read GetMessage;
property ExtensionsMin: LongInt read FExtensionsMin write FExtensionsMin;
property ExtensionsMax: LongInt read FExtensionsMax write FExtensionsMax;
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
function GetAsProtoString: RawByteString; override;
end;
TpbProtoPackage = class(TpbProtoNode)
protected
FFileName : RawByteString;
FName : RawByteString;
FMessages : array of TpbProtoMessage;
FImports : array of RawByteString;
FImportedPackages : array of TpbProtoPackage;
FOptions : array of TpbProtoOption;
FEnums : array of TpbProtoEnum;
function GetEnumCount: Integer;
function GetEnum(const Idx: Integer): TpbProtoEnum;
function GetEnumByName(const AName: RawByteString): TpbProtoEnum;
public
constructor Create;
destructor Destroy; override;
property FileName: RawByteString read FFileName write FFileName;
property Name: RawByteString read FName write FName;
procedure AddMessage(const M: TpbProtoMessage);
function GetMessageCount: Integer;
function GetMessage(const Idx: Integer): TpbProtoMessage;
function GetMessageByName(const AName: RawByteString): TpbProtoMessage;
procedure AddImport(const Path: RawByteString);
function GetImportCount: Integer;
function GetImport(const Idx: Integer): RawByteString;
procedure AddImportedPackage(const Package: TpbProtoPackage);
function GetImportedPackageCount: Integer;
function GetImportedPackage(const Idx: Integer): TpbProtoPackage;
function GetImportedPackageByName(const AName: RawByteString): TpbProtoPackage;
procedure AddOption(const Option: TpbProtoOption);
function GetOptionCount: Integer;
function GetOption(const Idx: Integer): TpbProtoOption;
procedure AddEnum(const E: TpbProtoEnum);
property EnumCount: Integer read GetEnumCount;
property Enum[const Idx: Integer]: TpbProtoEnum read GetEnum;
function ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
function ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode; override;
function GetAsProtoString: RawByteString; override;
end;
TpbProtoNodeFactory = class
public
function CreatePackage: TpbProtoPackage; virtual;
function CreateMessage(const AParentNode: TpbProtoNode): TpbProtoMessage; virtual;
function CreateField(const AParentMessage: TpbProtoMessage): TpbProtoField; virtual;
function CreateFieldType(const AParentField: TpbProtoField): TpbProtoFieldType; virtual;
function CreateLiteral(const AParentNode: TpbProtoNode): TpbProtoLiteral; virtual;
function CreateEnum(const AParentNode: TpbProtoNode): TpbProtoEnum; virtual;
function CreateEnumValue(const AParentEnum: TpbProtoEnum): TpbProtoEnumValue; virtual;
end;
{ Default ProtoNode factory }
function GetDefaultProtoNodeFactory: TpbProtoNodeFactory;
implementation
uses
{ Fundamentals }
flcStrings,
flcFloats;
const
pbCRLF = RawByteString(#13#10);
ProtoFieldCardinalityStr : array[TpbProtoFieldCardinality] of RawByteString = (
'',
'required',
'optional',
'repeated'
);
ProtoFieldTypeStr : array[TpbProtoFieldBaseType] of RawByteString = (
'',
'double',
'float',
'int32',
'int64',
'uint32',
'uint64',
'sint32',
'sint64',
'fixed32',
'fixed64',
'sfixed32',
'sfixed64',
'bool',
'string',
'bytes',
''
);
SErr_IdentifierNotDefined = 'Identifier not defined (%s)';
SErr_IdentifierNotAValue = 'Identifier not a value (%s)';
{ Helper functions }
procedure pbSplitIdentifier(const AIdentifier: RawByteString;
var ALeftName, ARightIdentifier: RawByteString);
begin
StrSplitAtCharB(AIdentifier, '.', ALeftName, ARightIdentifier, True);
end;
{ TpbProtoNode }
function TpbProtoNode.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
begin
raise EpbProtoNode.CreateFmt('%s.ResolveValue not implemented', [ClassName]);
end;
function TpbProtoNode.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
begin
raise EpbProtoNode.CreateFmt('%s.ResolveType not implemented', [ClassName]);
end;
function TpbProtoNode.ExpectResolvedValue(const AIdentifier: RawByteString): TpbProtoNode;
begin
Result := ResolveValue(AIdentifier, False);
if not Assigned(Result) then
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
end;
function TpbProtoNode.ExpectResolvedType(const AIdentifier: RawByteString): TpbProtoNode;
begin
Result := ResolveType(AIdentifier, False);
if not Assigned(Result) then
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
end;
function TpbProtoNode.GetAsProtoString: RawByteString;
begin
raise EpbProtoNode.CreateFmt('%s.GetAsProtoString not implemented', [ClassName]);
end;
{ TpbProtoEnumValue }
constructor TpbProtoEnumValue.Create(const AParentEnum: TpbProtoEnum);
begin
Assert(Assigned(AParentEnum));
inherited Create;
FParentEnum := AParentEnum;
end;
function TpbProtoEnumValue.GetAsProtoString: RawByteString;
begin
Result := FName + ' = ' + IntToStringB(FValue) + ';';
end;
{ TpbProtoEnum }
constructor TpbProtoEnum.Create(const AParentNode: TpbProtoNode);
begin
Assert(Assigned(AParentNode));
inherited Create;
end;
procedure TpbProtoEnum.Add(const V: TpbProtoEnumValue);
var L : Integer;
begin
L := Length(FValues);
SetLength(FValues, L + 1);
FValues[L] := V;
end;
function TpbProtoEnum.GetValueCount: Integer;
begin
Result := Length(FValues);
end;
function TpbProtoEnum.GetValue(const Idx: Integer): TpbProtoEnumValue;
begin
Assert((Idx >= 0) and (Idx < Length(FValues)));
Result := FValues[Idx];
end;
function TpbProtoEnum.GetValueByName(const AName: RawByteString): TpbProtoEnumValue;
var
I : Integer;
V : TpbProtoEnumValue;
begin
for I := 0 to Length(FValues) - 1 do
begin
V := FValues[I];
if V.FName = AName then
begin
Result := V;
exit;
end;
end;
Result := nil;
end;
function TpbProtoEnum.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
begin
Result := GetValueByName(AIdentifier);
end;
function TpbProtoEnum.GetAsProtoString: RawByteString;
var I, L : Integer;
begin
Result := 'enum ' + FName + ' {' + pbCRLF;
L := Length(FValues);
for I := 0 to L - 1 do
Result := Result + FValues[I].GetAsProtoString + pbCRLF;
Result := Result + '}';
end;
{ TpbProtoLiteral }
constructor TpbProtoLiteral.Create(const AParentNode: TpbProtoNode);
begin
Assert(Assigned(AParentNode));
inherited Create;
FParentNode := AParentNode;
end;
function TpbProtoLiteral.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
begin
if AChildrenOnly then
Result := nil
else
Result := FParentNode.ResolveValue(AIdentifier, False);
end;
function TpbProtoLiteral.GetAsProtoString: RawByteString;
begin
case FLiteralType of
pltNone : Result := '';
pltInteger : Result := IntToStringB(FLiteralInt);
pltFloat : Result := FloatToStringB(FLiteralFloat);
pltString : Result := StrQuoteB(FLiteralStr, '"');
pltBoolean : Result := iifB(FLiteralBool, 'true', 'false');
pltIdentifier : Result := FLiteralIden;
else
raise EpbProtoNode.Create('Invalid literal type');
end;
end;
function TpbProtoLiteral.LiteralIdenValue: TpbProtoNode;
begin
if FLiteralType <> pltIdentifier then
raise EpbProtoNode.Create('Not a identifier type');
Result := ResolveValue(FLiteralIden, False);
end;
{ TpbProtoFieldType }
constructor TpbProtoFieldType.Create(const AParentField: TpbProtoField);
begin
Assert(Assigned(AParentField));
inherited Create;
FParentField := AParentField;
end;
function TpbProtoFieldType.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
begin
if AChildrenOnly then
Result := nil
else
Result := FParentField.ResolveType(AIdentifier, False);
end;
function TpbProtoFieldType.GetAsProtoString: RawByteString;
begin
if FBaseType = pftIdentifier then
Result := FIdenStr
else
Result := ProtoFieldTypeStr[FBaseType];
end;
function TpbProtoFieldType.IsSimpleType: Boolean;
begin
Result := not (FBaseType in [pftNone, pftIdentifier]);
end;
function TpbProtoFieldType.IsIdenType: Boolean;
begin
Result := FBaseType = pftIdentifier;
end;
function TpbProtoFieldType.IdenType: TpbProtoNode;
begin
if not IsIdenType then
raise EpbProtoNode.Create('Not an identifier type');
Result := ExpectResolvedType(FIdenStr);
end;
{ TpbProtoField }
constructor TpbProtoField.Create(const AParentMessage: TpbProtoMessage; const AFactory: TpbProtoNodeFactory);
begin
Assert(Assigned(AParentMessage));
Assert(Assigned(AFactory));
inherited Create;
FParentMessage := AParentMessage;
FDefaultValue := AFactory.CreateLiteral(self);
FFieldType := AFactory.CreateFieldType(self);
end;
destructor TpbProtoField.Destroy;
var I : Integer;
begin
for I := Length(FOptions) - 1 downto 0 do
FreeAndNil(FOptions);
FreeAndNil(FFieldType);
FreeAndNil(FDefaultValue);
inherited Destroy;
end;
procedure TpbProtoField.SetFieldType(const Value: TpbProtoFieldType);
begin
FreeAndNil(FFieldType);
FFieldType := Value;
end;
procedure TpbProtoField.SetDefaultValue(const Value: TpbProtoLiteral);
begin
FreeAndNil(FDefaultValue);
FDefaultValue := Value;
end;
procedure TpbProtoField.AddOption(const Option: TpbProtoOption);
var
L : Integer;
begin
L := Length(FOptions);
SetLength(FOptions, L + 1);
FOptions[L] := Option;
end;
function TpbProtoField.GetOptionCount: Integer;
begin
Result := Length(FOptions);
end;
function TpbProtoField.GetOption(const Idx: Integer): TpbProtoOption;
begin
Assert((Idx >= 0) and (Idx < Length(FOptions)));
Result := FOptions[Idx];
end;
function TpbProtoField.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
begin
if AChildrenOnly then
Result := nil
else
Result := FParentMessage.ResolveValue(AIdentifier, False);
end;
function TpbProtoField.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
begin
if AChildrenOnly then
Result := nil
else
Result := FParentMessage.ResolveType(AIdentifier, False);
end;
function TpbProtoField.GetAsProtoString: RawByteString;
begin
Result :=
ProtoFieldCardinalityStr[FCardinality] + ' ' +
FFieldType.GetAsProtoString + ' ' +
FName + ' = ' +
IntToStringB(FTagID) + ';';
end;
{ TpbProtoMessage }
constructor TpbProtoMessage.Create(const AParentNode: TpbProtoNode);
begin
Assert(Assigned(AParentNode));
inherited Create;
FParentNode := AParentNode;
end;
destructor TpbProtoMessage.Destroy;
var I : Integer;
begin
for I := Length(FEnums) - 1 downto 0 do
FreeAndNil(FEnums[I]);
for I := Length(FFields) - 1 downto 0 do
FreeAndNil(FFields[I]);
for I := Length(FMessages) - 1 downto 0 do
FreeAndNil(FMessages[I]);
inherited Destroy;
end;
procedure TpbProtoMessage.AddField(const F: TpbProtoField);
var L : Integer;
begin
L := Length(FFields);
SetLength(FFields, L + 1);
FFields[L] := F;
end;
function TpbProtoMessage.GetFieldCount: Integer;
begin
Result := Length(FFields);
end;
function TpbProtoMessage.GetField(const Idx: Integer): TpbProtoField;
begin
Assert((Idx >= 0) and (Idx < Length(FFields)));
Result := FFields[Idx];
end;
function TpbProtoMessage.GetFieldByTagID(const ATagID: Integer): TpbProtoField;
var
I : Integer;
F : TpbProtoField;
begin
for I := 0 to Length(FFields) - 1 do
begin
F := GetField(I);
if F.FTagID = ATagID then
begin
Result := F;
exit;
end;
end;
Result := nil;
end;
procedure TpbProtoMessage.AddEnum(const E: TpbProtoEnum);
var L : Integer;
begin
L := Length(FEnums);
SetLength(FEnums, L + 1);
FEnums[L] := E;
end;
function TpbProtoMessage.GetEnumCount: Integer;
begin
Result := Length(FEnums);
end;
function TpbProtoMessage.GetEnum(const Idx: Integer): TpbProtoEnum;
begin
Assert((Idx >= 0) and (Idx < Length(FEnums)));
Result := FEnums[Idx];
end;
function TpbProtoMessage.GetEnumByName(const AName: RawByteString): TpbProtoEnum;
var
I : Integer;
E : TpbProtoEnum;
begin
for I := 0 to GetEnumCount - 1 do
begin
E := GetEnum(I);
if E.FName = AName then
begin
Result := E;
exit;
end;
end;
Result := nil;
end;
procedure TpbProtoMessage.AddMessage(const M: TpbProtoMessage);
var L : Integer;
begin
L := Length(FMessages);
SetLength(FMessages, L + 1);
FMessages[L] := M;
end;
function TpbProtoMessage.GetMessageCount: Integer;
begin
Result := Length(FMessages);
end;
function TpbProtoMessage.GetMessage(const Idx: Integer): TpbProtoMessage;
begin
Assert((Idx >= 0) and (Idx < Length(FMessages)));
Result := FMessages[Idx];
end;
function TpbProtoMessage.GetMessageByName(const AName: RawByteString): TpbProtoMessage;
var
I : Integer;
M : TpbProtoMessage;
begin
for I := 0 to GetMessageCount - 1 do
begin
M := GetMessage(I);
if M.FName = AName then
begin
Result := M;
exit;
end;
end;
Result := nil;
end;
function TpbProtoMessage.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
var
I : Integer;
E : TpbProtoEnum;
M : TpbProtoMessage;
N, S : RawByteString;
begin
for I := 0 to GetEnumCount - 1 do
begin
E := GetEnum(I);
Result := E.ResolveValue(AIdentifier, True);
if Assigned(Result) then
exit;
end;
pbSplitIdentifier(AIdentifier, N, S);
M := GetMessageByName(N);
if Assigned(M) then
begin
if S = '' then
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotAValue, [AIdentifier]);
Result := M.ResolveValue(S, True);
if Assigned(Result) then
exit
else
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
end;
if AChildrenOnly then
Result := nil
else
Result := FParentNode.ResolveValue(AIdentifier, False);
end;
function TpbProtoMessage.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
var
M : TpbProtoMessage;
E : TpbProtoEnum;
N, S : RawByteString;
begin
pbSplitIdentifier(AIdentifier, N, S);
M := GetMessageByName(N);
if Assigned(M) then
begin
if S = '' then
Result := M
else
begin
Result := M.ResolveType(S, True);
if not Assigned(Result) then
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
end;
exit;
end;
E := GetEnumByName(AIdentifier);
if Assigned(E) then
begin
Result := E;
exit;
end;
if AChildrenOnly then
Result := nil
else
Result := FParentNode.ResolveType(AIdentifier, False);
end;
function TpbProtoMessage.GetAsProtoString: RawByteString;
var
S : RawByteString;
I : Integer;
begin
S := 'message ' + FName + ' {' + pbCRLF;
for I := 0 to GetMessageCount - 1 do
S := S + GetMessage(I).GetAsProtoString;
for I := 0 to GetEnumCount - 1 do
S := S + GetEnum(I).GetAsProtoString;
for I := 0 to GetFieldCount - 1 do
S := S + GetField(I).GetAsProtoString;
S := S + '}' + pbCRLF;
Result := S;
end;
{ TpbProtoOption }
constructor TpbProtoOption.Create(const AFactory: TpbProtoNodeFactory);
begin
Assert(Assigned(AFactory));
inherited Create;
FValue := AFactory.CreateLiteral(self);
end;
destructor TpbProtoOption.Destroy;
begin
FreeAndNil(FValue);
inherited Destroy;
end;
procedure TpbProtoOption.SetValue(const Value: TpbProtoLiteral);
begin
FreeAndNil(FValue);
FValue := Value;
end;
{ TpbProtoPackage }
constructor TpbProtoPackage.Create;
begin
inherited Create;
end;
destructor TpbProtoPackage.Destroy;
var I : Integer;
begin
for I := Length(FImportedPackages) - 1 downto 0 do
FreeAndNil(FImportedPackages[I]);
for I := Length(FOptions) - 1 downto 0 do
FreeAndNil(FOptions[I]);
for I := Length(FMessages) - 1 downto 0 do
FreeAndNil(FMessages[I]);
inherited Destroy;
end;
procedure TpbProtoPackage.AddMessage(const M: TpbProtoMessage);
var
L : Integer;
begin
L := Length(FMessages);
SetLength(FMessages, L + 1);
FMessages[L] := M;
end;
function TpbProtoPackage.GetMessageCount: Integer;
begin
Result := Length(FMessages);
end;
function TpbProtoPackage.GetMessage(const Idx: Integer): TpbProtoMessage;
begin
Assert((Idx >= 0) and (Idx < Length(FMessages)));
Result := FMessages[Idx];
end;
function TpbProtoPackage.GetMessageByName(const AName: RawByteString): TpbProtoMessage;
var
I : Integer;
M : TpbProtoMessage;
begin
for I := 0 to GetMessageCount - 1 do
begin
M := GetMessage(I);
if M.FName = AName then
begin
Result := M;
exit;
end;
end;
Result := nil;
end;
procedure TpbProtoPackage.AddImport(const Path: RawByteString);
var
L : Integer;
begin
L := Length(FImports);
SetLength(FImports, L + 1);
FImports[L] := Path;
end;
function TpbProtoPackage.GetImportCount: Integer;
begin
Result := Length(FImports);
end;
function TpbProtoPackage.GetImport(const Idx: Integer): RawByteString;
begin
Assert((Idx >= 0) and (Idx < Length(FImports)));
Result := FImports[Idx];
end;
procedure TpbProtoPackage.AddImportedPackage(const Package: TpbProtoPackage);
var
L : Integer;
begin
L := Length(FImportedPackages);
SetLength(FImportedPackages, L + 1);
FImportedPackages[L] := Package;
end;
function TpbProtoPackage.GetImportedPackageCount: Integer;
begin
Result := Length(FImportedPackages);
end;
function TpbProtoPackage.GetImportedPackage(const Idx: Integer): TpbProtoPackage;
begin
Assert((Idx >= 0) and (Idx < Length(FImportedPackages)));
Result := FImportedPackages[Idx];
end;
function TpbProtoPackage.GetImportedPackageByName(const AName: RawByteString): TpbProtoPackage;
var
I : Integer;
P : TpbProtoPackage;
begin
for I := 0 to GetImportedPackageCount - 1 do
begin
P := GetImportedPackage(I);
if P.FName = AName then
begin
Result := P;
exit;
end;
end;
Result := nil;
end;
procedure TpbProtoPackage.AddOption(const Option: TpbProtoOption);
var
L : Integer;
begin
L := Length(FOptions);
SetLength(FOptions, L + 1);
FOptions[L] := Option;
end;
function TpbProtoPackage.GetOptionCount: Integer;
begin
Result := Length(FOptions);
end;
function TpbProtoPackage.GetOption(const Idx: Integer): TpbProtoOption;
begin
Assert((Idx >= 0) and (Idx < Length(FOptions)));
Result := FOptions[Idx];
end;
procedure TpbProtoPackage.AddEnum(const E: TpbProtoEnum);
var L : Integer;
begin
L := Length(FEnums);
SetLength(FEnums, L + 1);
FEnums[L] := E;
end;
function TpbProtoPackage.GetEnumCount: Integer;
begin
Result := Length(FEnums);
end;
function TpbProtoPackage.GetEnum(const Idx: Integer): TpbProtoEnum;
begin
Assert((Idx >= 0) and (Idx < Length(FEnums)));
Result := FEnums[Idx];
end;
function TpbProtoPackage.GetEnumByName(const AName: RawByteString): TpbProtoEnum;
var
I : Integer;
E : TpbProtoEnum;
begin
for I := 0 to GetEnumCount - 1 do
begin
E := GetEnum(I);
if E.FName = AName then
begin
Result := E;
exit;
end;
end;
Result := nil;
end;
function TpbProtoPackage.ResolveValue(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
var
I : Integer;
E : TpbProtoEnum;
M : TpbProtoMessage;
P : TpbProtoPackage;
N, S : RawByteString;
begin
for I := 0 to GetEnumCount - 1 do
begin
E := GetEnum(I);
Result := E.ResolveValue(AIdentifier, True);
if Assigned(Result) then
exit;
end;
pbSplitIdentifier(AIdentifier, N, S);
M := GetMessageByName(N);
if Assigned(M) then
begin
if S = '' then
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotAValue, [AIdentifier]);
Result := M.ResolveValue(S, True);
if Assigned(Result) then
exit
else
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
end;
for I := 0 to GetMessageCount - 1 do
begin
M := GetMessage(I);
Result := M.ResolveValue(AIdentifier, True);
if Assigned(Result) then
exit;
end;
P := GetImportedPackageByName(N);
if Assigned(P) then
begin
if S = '' then
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotAValue, [AIdentifier]);
Result := P.ResolveValue(S, True);
if Assigned(Result) then
exit
else
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
end;
for I := 0 to GetImportedPackageCount - 1 do
begin
P := GetImportedPackage(I);
Result := P.ResolveValue(AIdentifier, True);
if Assigned(Result) then
exit;
end;
Result := nil;
end;
function TpbProtoPackage.ResolveType(const AIdentifier: RawByteString; const AChildrenOnly: Boolean): TpbProtoNode;
var
M : TpbProtoMessage;
E : TpbProtoEnum;
P : TpbProtoPackage;
N, S : RawByteString;
I : Integer;
begin
pbSplitIdentifier(AIdentifier, N, S);
M := GetMessageByName(N);
if Assigned(M) then
begin
if S = '' then
Result := M
else
begin
Result := M.ResolveType(S, True);
if not Assigned(Result) then
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
end;
exit;
end;
E := GetEnumByName(AIdentifier);
if Assigned(E) then
begin
Result := E;
exit;
end;
P := GetImportedPackageByName(N);
if Assigned(P) then
begin
if S = '' then
Result := P
else
begin
Result := P.ResolveType(S, True);
if not Assigned(Result) then
raise EpbProtoNode.CreateFmt(SErr_IdentifierNotDefined, [AIdentifier]);
end;
exit;
end;
for I := 0 to GetImportedPackageCount - 1 do
begin
Result := GetImportedPackage(I).ResolveType(AIdentifier, True);
if Assigned(Result) then
exit;
end;
Result := nil;
end;
function TpbProtoPackage.GetAsProtoString: RawByteString;
var
I : Integer;
S : RawByteString;
begin
S := '';
if FName <> '' then
S := S + 'package ' + FName + ';' + pbCRLF + pbCRLF;
for I := 0 to GetMessageCount - 1 do
S := S + GetMessage(I).GetAsProtoString;
Result := S;
end;
{ TpbProtoNodeFactory }
function TpbProtoNodeFactory.CreatePackage: TpbProtoPackage;
begin
Result := TpbProtoPackage.Create;
end;
function TpbProtoNodeFactory.CreateMessage(const AParentNode: TpbProtoNode): TpbProtoMessage;
begin
Result := TpbProtoMessage.Create(AParentNode);
end;
function TpbProtoNodeFactory.CreateField(const AParentMessage: TpbProtoMessage): TpbProtoField;
begin
Result := TpbProtoField.Create(AParentMessage, self);
end;
function TpbProtoNodeFactory.CreateFieldType(const AParentField: TpbProtoField): TpbProtoFieldType;
begin
Result := TpbProtoFieldType.Create(AParentField);
end;
function TpbProtoNodeFactory.CreateLiteral(const AParentNode: TpbProtoNode): TpbProtoLiteral;
begin
Result := TpbProtoLiteral.Create(AParentNode);
end;
function TpbProtoNodeFactory.CreateEnum(const AParentNode: TpbProtoNode): TpbProtoEnum;
begin
Result := TpbProtoEnum.Create(AParentNode);
end;
function TpbProtoNodeFactory.CreateEnumValue(const AParentEnum: TpbProtoEnum): TpbProtoEnumValue;
begin
Result := TpbProtoEnumValue.Create(AParentEnum);
end;
{ Default ProtoNode factory }
var
DefaultProtoNodeFactory: TpbProtoNodeFactory = nil;
function GetDefaultProtoNodeFactory: TpbProtoNodeFactory;
begin
if not Assigned(DefaultProtoNodeFactory) then
DefaultProtoNodeFactory := TpbProtoNodeFactory.Create;
Result := DefaultProtoNodeFactory;
end;
initialization
finalization
FreeAndNil(DefaultProtoNodeFactory);
end.