📄 uicdeclarationassembler.pas
字号:
{Assembles the declaration of the identifier.
~param Identifier the identifier to assemble the declaration of }
procedure TICDeclarationAssembler.GetDeclaration(Identifier: TIdentifier);
begin
PrepareAssembling; //create new, empty declaration
inherited GetDeclaration(Identifier); //assemble the declaration
CheckText; //check for any cached/buffered text
end;
{Assembles the declaration of a part of an identifier.
~param Identifier the identifier to assemble the declaration of
~param Expr an expression as part of the declaration of the identifier }
procedure TICDeclarationAssembler.GetDeclarationPart(Identifier: TIdentifier;
const Expr: String);
begin
PrepareAssembling; //create new, empty declaration
SetSourceIdentifier(Identifier); //set the identifier
ExprText(Expr); //assemble the expression
CheckText; //check for any cached/buffered text
end;
{Will be called for all reserved words.
~param Word a string of one ore more reserved words }
procedure TICDeclarationAssembler.ReservedWord(const Word: String);
begin
AddPascalToken(Word, icpcReservedWord); //add a node for the reserved word
end;
{Will be called for all texts of identifiers.
~param Text a text with an identifier (or multiple separated by ".") }
procedure TICDeclarationAssembler.IdentifierText(const Text: String);
begin
AddPascalToken(Text, icpcIdentifier); //add name of the identifier
end;
{Will be called for all names of identifier-type identifiers. This means it
will be called by the class ~[linkClass TIdentType] for any known type
identifier. Normally a link on the identifier should be generated with the
text Ident.~[link TIdentifier.Name Name].
~param Ident a type identifier to that a link should be generated }
procedure TICDeclarationAssembler.TypeIdentifierText(Ident: TIdentifier);
begin
CreateLink(Ident); //add link to the type
end;
(*
{Will be called for a text of a type identifier. If the identifier is known it
will call ~[link TypeIdentifierText] instead. Because the type is not known
only it name could be shown.
~param TypeStr the text of the type identifier }
procedure TICDeclarationAssembler.TypeText(TypeStr: String);
begin
IdentifierText(TextStr); //treat as normal unknown identifier
end;
*)
{Will be called for all expressions, for instance like used as the index of an
array or the value of a constant. The text should be parsed and identifiers
should be underlaid with a link to their declaration if possible.
~param ExprStr the text of the expression
~todo reimplement, I'm not really happy with it, but it does work in most
cases
~todo FileGiven has to check for Unit-Aliases! }
procedure TICDeclarationAssembler.ExprText(const ExprStr: String);
var SourceRec :TRecordType; //current record-like type
State :( //general state in the expression
sNo, //after operator or similar character
sIdent, //after an identifier (or dot)
sBrace, //after a opening brace or bracket
sString); //after a string
Parser :TTokenParser; //parser of the expression
Token :String; //a token in the expression
Next :String; //the next token after an identifier
FileGiven :Boolean; //file of identifier was given
Position :TPosition; //position to start search
Ident :TIdentifier; //identifiers in the expression
dot :Integer; //index of a "." in the token
//file of record-like type to search identifiers in
RecIdent :TRecordType; //used record-like type
IdentName :String; //a used member of a record-like type
begin
Assert(Assigned(SourceIdent));
Assert(Assigned(SourceIdent.InFile));
if SourceIdent is TRecordType then //get current record-like type
SourceRec := TRecordType(SourceIdent) //is is one, use it
else
SourceRec := SourceIdent.MemberOf; //use its record-like type
if Assigned(SourceIdent) then //get position to search from
begin
if SourceIdent is TRecordType then //if it is a record-like type
Position := SourceIdent.Position //use its position
else
Position := SourceIdent.ForwardDefPos; //use always the first declaration
end
else
begin
Position.Row := -1; //search from the beginning
Position.Column := 1;
end;
Parser := TTokenParser.Create; //create tokenizer
try
Parser.PascalDialect := SourceIdent.InFile.PascalDialect;
Parser.ParseString(ExprStr); //parse expression text
State := sNo; //begin without a special state
while Parser.GetIdentWithPointsToken(Token) do //parse each token
begin //is an identifier?
if (Token <> '') and (Token[1] in StartIdentifierChars) then
begin
State := sIdent; //next token is after identifier
if LowerCase(Token) = 'nil' then //is nil?
AddPascalToken(Token, icpcReservedWord) //just add to the expression
else
begin
Text(' '); //add a space before it
Parser.PushPosition;
Parser.GetToken(Next); //preview the following token
Parser.PopPosition;
//not initialization of a record, i.e. a field of the record?
if Next <> ':' then
begin
dot := Pos('.', Token);
if Assigned(SourceRec) then //is in a record-like type?
begin
if dot = 0 then
dot := Length(Token) + 1;
//search the identifier in it by this name
Ident := SourceRec.IdentList.GetIdentByName(copy(Token, 1,
dot - 1));
if Assigned(Ident) then
begin
CreateLink(Ident); //add link to it
Delete(Token, 1, dot); //remove identifier
end
else
dot := Pos('.', Token);
end
else
Ident := nil; //not found so far
if not Assigned(Ident) then
begin
//search the identifier by this name (globally)
Ident := FGenerator.FindIdentifier(Token, SourceIdent.InFile,
Position);
if Assigned(Ident) then //the identifier found?
begin
FileGiven := (dot <> 0) and //file name given?
(Length(Ident.InFile.InternalFileName) =
dot - 1) and
(CompareText(Ident.InFile.InternalFileName,
Copy(Token, 1, dot - 1)) = 0);
if dot = 0 then //get full length of identifier or file
dot := Length(Token) + 1;
CreateLink(Ident, FileGiven); //create link to identifier
if FileGiven then //if file given
begin
Delete(Token, 1, dot); //delete it
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);
Text('.');
CreateLink(Ident); //append a link to it
end;
end; //while Token <> '' and Ident is TRecordType
if Token <> '' then //add any unknown members
begin
Text('.');
IdentifierText(Token); //add the text
end;
end //if assigned(Ident)
else
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.
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
Text(' '); //add a separating space
if Token[1] = '''' then //is a string?
AddPascalToken(Token, icpcString) //add formatted as string
else
Text(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?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -