📄 udocumentdoc.pas
字号:
dot := pos('.', Token);
if dot = 0 then
dot := length(Token);
end;
Delete(Token, 1, dot); //delete the identifier
end;
end;
if assigned(Ident) then //something found?
begin
//while members follow
while (Token <> '') and (Ident is TRecordType) do
begin
dot := pos('.', Token);
if dot = 0 then //get next member
IdentName := Token
else
IdentName := copy(Token, 1, dot - 1);
RecIdent := TRecordType(Ident); //search the member
Ident := RecIdent.FindMember(IdentName, SourceIdent.InFile,
False);
if assigned(Ident) then //member found?
begin
if dot = 0 then //delete it
Token := ''
else
Delete(Token, 1, dot);
//not documented?
if DoNotDocumentIdentifier(Ident) then
//just add the text
Result := Result + IdentifierText(IdentName)
else
//append a link to it
Result := Result + '.' + GetRecordFieldNameLink(Ident);
end;
end; //while Token <> '' and Ident is TRecordType
if Token <> '' then //add any unknown members
Result := Result + '.' + IdentifierText(Token);
end //if assigned(Ident)
else
Result := Result + IdentifierText(Token); //append text
end //if Next <> ':' //record-field initialization?
else
//link on field of record would be nice, but would have to know the
//record, hard if its an array of record or record of array etc.
Result := Result + IdentifierText(Token);
end //if not 'nil'
end //if identifier or reserved word
else
begin
if (State <> sBrace) and //no space after opening brace
((length(Token) <> 1) or //not a single special character?
(not (Token[1] in [',', '.', '(', ')', ']']) and
((Token[1] <> '[') or (State <> sIdent)))) and
//no spaces between parts of strings
((State <> sString) or not (Token[1] in ['''', '#', '^'])) then
Result := Result + ' '; //add a separating space
if Token[1] = '''' then //is a string?
Result := Result + FormatStringToken(Token) //add formatted as string
else
Result := Result + HandleRawText(Token); //add text
//get state of the expression after this last token
if Token[1] in ['(', '['] then
State := sBrace
else
if (Token[1] in ['''', '#']) or
((Token[1] = '^') and (State <> sIdent)) then
State := sString
else
if Token[1] in [')', ']', '.', '^'] then
State := sIdent
else
State := sNo;
//needs a second token?
if (State = sString) and (Token[1] in ['#', '^']) and
Parser.GetToken(Token) then //and it is available?
//add character number or the escaped control character
Result := Result + HandleRawText(Token);
end; //else identifier or reserved word
end; //while Parser.GetIdentWithPointsToken
finally
Parser.Free; //free tokenizer
end;
end;
{Will be called for texts of a member used as read or write-attribute of a
property. The member is underlaid with a link to their declaration if
possible.
~param ReadWrite the text of the member as used by the read- or
write-attribute of a property
~param Prop the property whose attribute should be returned
~param SourceIdent the identifier from which the description that included this
attribute has been requested
~result the member as a link if possible }
function TDocumentDoc.PropertyReadWrite(const ReadWrite: String;
Prop: TProperty;
SourceIdent: TIdentifier): String;
var dot :Integer; //position of point in string
IdentName :String; //name of the identifier
Ident :TIdentifier; //the identifier
begin
assert(assigned(SourceIdent));
assert(assigned(SourceIdent.InFile));
assert(ReadWrite <> '');
Result := ReadWrite;
if assigned(Prop) and assigned(Prop.MemberOf) then
begin
//delete all whitespace for simpler parsing
Result := DeleteAllWhiteSpaces(Result);
dot := pos('.', Result); //get first identifier
if dot <> 0 then
begin
IdentName := copy(Result, 1, dot - 1); //extract first identifier
Delete(Result, 1, dot - 1); //the remnant (including dot)
end
else
begin
IdentName := Result; //only a simple identifier
Result := '';
end;
//search the identifier in the class
Ident := Prop.MemberOf.FindMember(IdentName, SourceIdent.InFile, True);
//check if identifier is not documented
if assigned(Ident) and DoNotDocumentIdentifier(Ident) then
Ident := nil;
if assigned(Ident) then //identifier found?
//generate a link on it
Result := GetRecordFieldNameLink(Ident) + IdentifierText(Result)
else //just return the text
Result := IdentifierText(IdentName) + IdentifierText(Result);
end;
end;
{Will be called for implements-attribute of properties. The interfaces are
underlaid with a link to their declaration if possible.
~param Prop the property whose implemented interface should be returned
~param SourceIdent the identifier from which the description that included the
property has been requested
~result the implemented interface as a link if possible }
function TDocumentDoc.PropertyImplements(Prop: TProperty;
SourceIdent: TIdentifier): String;
var Source :String; //list of redirected interfaces
List :TIdentifierList; //list of implemented interfaces
i :Integer; //general index
One, LC :String; //each implemented interface
Interf :TIdentifier; //the interface
Message :TGeneratorMessage; //the message to add
begin
assert(assigned(SourceIdent));
assert(assigned(SourceIdent.InFile));
Source := Prop.ImplementsInterfaces; //get definition of the attribute
List := Prop.MemberOf.Implementing; //get the implemented interfaces
{$IFOPT C+}
for i := 0 to List.Count - 1 do
assert(List[i] is TIdentType);
{$ENDIF}
Result := ''; //no text so far
while Source <> '' do //for each interface
begin
if Result <> '' then //not first interface?
Result := Result + HandleRawText(', '); //add separator
i := pos(', ', Source);
if i = 0 then //extract it
begin
One := Source;
Source := '';
end
else
begin
One := copy(Source, 1, i - 1);
Delete(Source, 1, i + 1);
end;
LC := LowerCase(One); //in lower case
//search the interface manually
Interf := FindIdentifier(One, Prop.InFile, Prop.MemberOf.Position);
if assigned(Interf) and //identifier found and valid kind?
((Interf is TRecordType) or (Interf is TIdentType)) and
not DoNotDocumentIdentifier(Interf) then
begin //add link to it
Result := Result + GetIdentNameLink(Interf, pos('.', One) <> 0);
//check if it is an implemented interface
if Interf is TIdentType then
Interf := TIdentType(Interf).GetFinalType;
if assigned(Interf) then //interface known?
begin
i := List.Count - 1; //search in list of the interfaces
while (i >= 0) and (Interf <> TIdentType(List[i]).GetFinalType) do
dec(i);
if i < 0 then //not found? => generate warning
begin
InitMessage(Message, DocumentDocMessagesID,
Ord(ddmkImplementedInterfaceOfPropertyDoesNotMatch),
Format(DocumentationTexts[dtImplementedInterfaceOfPropertyDoesNotMatch].T,
[One]));
Message.Position.Identifier := Prop;
AddMessage(Message);
end;
end;
end
else
Result := Result + IdentifierText(One); //just add the text
end;
end;
{Will be called for texts with an implemented interface and one of its methods.
It is used in classes that give another name of a method implementing a method
of an interface (at least that's what I understand by reading the help of that
syntax). The interface and the method should be underlaid with links to their
declarations if possible.
~param TheName the interface and its method separated by a dot
~param MethodOf the class that implements the interface
~param SourceIdent the identifier from that the description that included this
method-assigment has been requested
~result the name of the interface and the method as links if possible }
function TDocumentDoc.InterfaceMethod(const TheName: String;
MethodOf: TRecordType;
SourceIdent: TIdentifier): String;
var Name :String; //the name of the method
i :Integer; //general index
Interf :TIdentifier; //the interface of the method
Final :TType; //the real interface type
TheInterf :TRecordType; //interface defining the method
Method :TIdentifier; //the implemented method
List :TIdentifierList; //the list of implemented interfaces
Message :TGeneratorMessage; //the message to add
begin
assert(assigned(SourceIdent));
assert(assigned(SourceIdent.InFile));
Name := TheName; //use the name
i := pos('.', Name);
assert(i <> 0);
//search the interface manually
Interf := FindIdentifier(copy(Name, 1, i - 1), MethodOf.InFile,
MethodOf.Position);
if assigned(Interf) and //identifier found and valid kind?
((Interf is TRecordType) or (Interf is TIdentType)) and
not DoNotDocumentIdentifier(Interf) then
begin
//add link to the interface and the dot
Result := GetIdentNameLink(Interf) + IdentifierText('.');
Delete(Name, 1, i); //extract implemented method
Final := TType(Interf);
if Final is TIdentType then //get the final interface type
Final := TIdentType(Final).GetFinalType;
//interface known?
if (Final is TRecordType) and (TRecordType(Final).Kind = rkInterface) then
begin
//search the method in the interface and its ancestors
TheInterf := TRecordType(Final); //interface defining the method
repeat
Method := TheInterf.IdentList.GetIdentByName(Name); //search method
if not assigned(Method) then //get parent interface
TheInterf := TheInterf.GetParent;
//until found or no ancestor (known)
until assigned(Method) or not assigned(TheInterf);
//method found and documented?
if assigned(Method) and not DoNotDocumentIdentifier(Method) then
//add link to the method
Result := Result + GetRecordFieldNameLink(Method)
else
//just add the name of the method
Result := Result + IdentifierText(Name);
end
else
Result := Result + IdentifierText(Name); //just add the name of the method
//check if it is an implemented interface
if Interf is TIdentType then
Interf := TIdentType(Interf).GetFinalType;
if assigned(Interf) then
begin
List := MethodOf.Implementing; //get the implemented interfaces
{$IFOPT C+}
for i := 0 to List.Count - 1 do
assert(List[i] is TIdentType);
{$ENDIF}
i := List.Count - 1; //search in list of the interfaces
while (i >= 0) and (Interf <> TIdentType(List[i]).GetFinalType) do
dec(i);
if i < 0 then //not found? => generate warning
begin
InitMessage(Message, DocumentDocMessagesID,
Ord(ddmkInterfaceOfMethodNotImplemented),
Format(DocumentationTexts[dtInterfaceOfMethodNotImplemented].T,
[Interf.Name]));
Message.Position.Identifier := MethodOf;
AddMessage(Message);
end;
end; //if assigned(Interf)
end //if identifier found and valid kind
else
Result := IdentifierText(Name); //just use the text
end;
{Will be called for texts with the name of a method of the given record-like
type. It is used in classes that give another name of a method implementing a
method of an interface (at least that's what I understand by reading the help
of that syntax). The method should be underlaid with a link to its declaration
if possible.
~param Name the name of a method in that record-like type
~param MethodOf the record-like type that contains that method
~param SourceIdent the identifier from that the description that included this
method-assigment has been requested
~result the name of the method as a link if possible }
function TDocumentDoc.MethodName(const Name: String; MethodOf: TRecordType;
SourceIdent: TIdentifier): String;
var Ident :TIdentifier; //the identifier
begin
assert(assigned(SourceIdent));
assert(assigned(SourceIdent.InFile));
assert(Name <> '');
if assigned(MethodOf) then //only valid in classes
begin
assert(pos(' ', Name) = 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -