codetools: code completion for string iterators

git-svn-id: trunk@22412 -
This commit is contained in:
mattias 2009-11-03 23:03:27 +00:00
parent 87b819f60f
commit a0bc0d475c
3 changed files with 227 additions and 13 deletions

View File

@ -319,7 +319,8 @@ type
ContextLearn: boolean = true // true = learn policies from Source
): boolean;
function GetIndents(const Source: string; Positions: TFABPositionIndents;
NewNestedComments: boolean; UseLineStart: boolean
NewNestedComments: boolean; UseLineStart: boolean;
ContextLearn: boolean = true // true = learn policies from Source
): boolean;
procedure GetDefaultSrcIndent(const Source: string; CleanPos: integer;
NewNestedComments: boolean;
@ -1528,7 +1529,7 @@ end;
function TFullyAutomaticBeautifier.GetIndents(const Source: string;
Positions: TFABPositionIndents; NewNestedComments: boolean;
UseLineStart: boolean): boolean;
UseLineStart: boolean; ContextLearn: boolean): boolean;
var
Needed: LongInt;
@ -1583,9 +1584,11 @@ begin
inc(Item^.CleanPos);
end;
Policies:=TFABPolicies.Create;
Policies:=nil;
Stack:=TFABBlockStack.Create;
try
if ContextLearn then
Policies:=TFABPolicies.Create;
{$IFDEF ShowCodeBeautifierLearn}
Policies.Code:=TCodeBuffer.Create;
Policies.Code.Source:=Source;
@ -1655,19 +1658,22 @@ begin
end;
end;
// parse source behind
ParseSource(Source,Item^.CleanPos,length(Source)+1,NewNestedComments,Stack,Policies);
{$IFDEF VerboseIndenter}
DebugLn(['TFullyAutomaticBeautifier.GetIndent parsed source behind']);
{$ENDIF}
for ItemIndex:=0 to Positions.Count-1 do begin
Item:=@Positions.Items[ItemIndex];
if (not Item^.Indent.IndentValid) and (Item^.Block.Typ<>bbtNone) then
if CheckPolicies(Policies,Item) then exit(true);
if Policies<>nil then begin
// parse source behind
ParseSource(Source,Item^.CleanPos,length(Source)+1,NewNestedComments,Stack,Policies);
{$IFDEF VerboseIndenter}
DebugLn(['TFullyAutomaticBeautifier.GetIndent parsed source behind']);
{$ENDIF}
for ItemIndex:=0 to Positions.Count-1 do begin
Item:=@Positions.Items[ItemIndex];
if (not Item^.Indent.IndentValid) and (Item^.Block.Typ<>bbtNone) then
if CheckPolicies(Policies,Item) then exit(true);
end;
end;
finally
Stack.Free;
FreeAndNil(Policies.Code);
if Policies<>nil then
FreeAndNil(Policies.Code);
Policies.Free;
end;

View File

@ -170,6 +170,8 @@ type
SourceChangeCache: TSourceChangeCache);
function CheckLocalVarAssignmentSyntax(CleanCursorPos: integer;
out VarNameAtom,AssignmentOperator,TermAtom: TAtomPosition): boolean;
function CheckLocalVarForInSyntax(CleanCursorPos: integer;
out VarNameAtom,TermAtom: TAtomPosition): boolean;
function AddLocalVariable(CleanCursorPos: integer; OldTopLine: integer;
VariableName, VariableType, VariableTypeUnitName: string;
out NewPos: TCodeXYPosition; out NewTopLine: integer;
@ -186,6 +188,10 @@ type
OldTopLine: integer; CursorNode: TCodeTreeNode;
var NewPos: TCodeXYPosition; var NewTopLine: integer;
SourceChangeCache: TSourceChangeCache): boolean;
function CompleteLocalVariableForIn(CleanCursorPos,
OldTopLine: integer; CursorNode: TCodeTreeNode;
var NewPos: TCodeXYPosition; var NewTopLine: integer;
SourceChangeCache: TSourceChangeCache): boolean;
function CompleteLocalVariableByParameter(CleanCursorPos,
OldTopLine: integer; CursorNode: TCodeTreeNode;
var NewPos: TCodeXYPosition; var NewTopLine: integer;
@ -869,6 +875,42 @@ begin
Result:=TermAtom.EndPos>TermAtom.StartPos;
end;
function TCodeCompletionCodeTool.CheckLocalVarForInSyntax(
CleanCursorPos: integer; out VarNameAtom, TermAtom: TAtomPosition): boolean;
// check for: for VarName in Term do
var
InAtomEndPos: LongInt;
begin
Result:=false;
MoveCursorToCleanPos(CleanCursorPos);
// find variable name
GetIdentStartEndAtPosition(Src,CleanCursorPos,
VarNameAtom.StartPos,VarNameAtom.EndPos);
//debugln('TCodeCompletionCodeTool.CheckLocalVarAssignmentSyntax A ',GetAtom(VarNameAtom),' "',copy(Src,CleanCursorPos,10),'"');
if VarNameAtom.StartPos=VarNameAtom.EndPos then exit;
MoveCursorToAtomPos(VarNameAtom);
if AtomIsKeyWord then exit;
// find 'in' operator
ReadNextAtom;
if not UpAtomIs('IN') then exit;
InAtomEndPos:=CurPos.EndPos;
// find 'for' keyword
MoveCursorToCleanPos(VarNameAtom.StartPos);
ReadPriorAtom;
if not UpAtomIs('FOR') then exit;
// find term
MoveCursorToCleanPos(InAtomEndPos);
ReadNextAtom;
TermAtom.StartPos:=CurPos.StartPos;
TermAtom.EndPos:=FindEndOfExpression(TermAtom.StartPos);
Result:=TermAtom.EndPos>TermAtom.StartPos;
end;
function TCodeCompletionCodeTool.AddLocalVariable(
CleanCursorPos: integer; OldTopLine: integer;
VariableName, VariableType, VariableTypeUnitName: string;
@ -1151,6 +1193,76 @@ begin
NewType,MissingUnit,NewPos,NewTopLine,SourceChangeCache);
end;
function TCodeCompletionCodeTool.CompleteLocalVariableForIn(CleanCursorPos,
OldTopLine: integer; CursorNode: TCodeTreeNode; var NewPos: TCodeXYPosition;
var NewTopLine: integer; SourceChangeCache: TSourceChangeCache): boolean;
var
VarNameAtom: TAtomPosition;
TermAtom: TAtomPosition;
Params: TFindDeclarationParams;
NewType: String;
ExprType: TExpressionType;
MissingUnit: String;
begin
Result:=false;
{$IFDEF CTDEBUG}
DebugLn(' CompleteLocalVariableForIn: A');
{$ENDIF}
if not ((CursorNode.Desc=ctnBeginBlock)
or CursorNode.HasParentOfType(ctnBeginBlock)) then exit;
if CursorNode.Desc=ctnBeginBlock then
BuildSubTreeForBeginBlock(CursorNode);
CursorNode:=FindDeepestNodeAtPos(CleanCursorPos,true);
{$IFDEF CTDEBUG}
DebugLn(' CompleteLocalVariableForIn: B CheckLocalVarForInSyntax ...');
{$ENDIF}
// check assignment syntax
if not CheckLocalVarForInSyntax(CleanCursorPos,
VarNameAtom,TermAtom)
then
exit;
DebugLn(['TCodeCompletionCodeTool.CompleteLocalVariableForIn Var=',GetAtom(VarNameAtom),' Term=',GetAtom(TermAtom)]);
// search variable
ActivateGlobalWriteLock;
Params:=TFindDeclarationParams.Create;
try
{$IFDEF CTDEBUG}
DebugLn(' CompleteLocalVariableForIn: check if variable is already defined ...');
{$ENDIF}
// check if identifier exists
Result:=IdentifierIsDefined(VarNameAtom,CursorNode,Params);
if Result then begin
MoveCursorToCleanPos(VarNameAtom.StartPos);
ReadNextAtom;
RaiseExceptionFmt(ctsIdentifierAlreadyDefined,[GetAtom]);
end;
{$IFDEF CTDEBUG}
DebugLn(' CompleteLocalVariableForIn: Find type of term ...',
' Term="',copy(Src,TermAtom.StartPos,TermAtom.EndPos-TermAtom.StartPos),'"');
{$ENDIF}
// find type of term
NewType:=FindForInTypeAsString(TermAtom,CursorNode,Params,ExprType);
if NewType='' then
RaiseException('CompleteLocalVariableForIn Internal error: NewType=""');
finally
Params.Free;
DeactivateGlobalWriteLock;
end;
MissingUnit:='';
if (ExprType.Desc=xtContext)
and (ExprType.Context.Tool<>nil) then
MissingUnit:=GetUnitForUsesSection(ExprType.Context.Tool);
Result:=AddVariable(CursorNode,CleanCursorPos,OldTopLine,GetAtom(VarNameAtom),
NewType,MissingUnit,NewPos,NewTopLine,SourceChangeCache);
end;
function TCodeCompletionCodeTool.CompleteLocalVariableByParameter(
CleanCursorPos, OldTopLine: integer; CursorNode: TCodeTreeNode;
var NewPos: TCodeXYPosition; var NewTopLine: integer;
@ -6789,6 +6901,11 @@ begin
CursorNode,NewPos,NewTopLine,SourceChangeCache);
if Result then exit;
// test if Local variable iterator (for i in j)
Result:=CompleteLocalVariableForIn(CleanCursorPos,OldTopLine,
CursorNode,NewPos,NewTopLine,SourceChangeCache);
if Result then exit;
// test if undeclared local variable as parameter (GetPenPos(x,y))
Result:=CompleteLocalVariableByParameter(CleanCursorPos,OldTopLine,
CursorNode,NewPos,NewTopLine,SourceChangeCache);

View File

@ -643,6 +643,9 @@ type
function FindTermTypeAsString(TermPos: TAtomPosition;
CursorNode: TCodeTreeNode; Params: TFindDeclarationParams;
out ExprType: TExpressionType): string;
function FindForInTypeAsString(TermPos: TAtomPosition;
CursorNode: TCodeTreeNode; Params: TFindDeclarationParams;
out ExprType: TExpressionType): string;
function IsTermEdgedBracket(TermPos: TAtomPosition;
out EdgedBracketsStartPos: integer): boolean;
function IsTermNamedPointer(TermPos: TAtomPosition;
@ -8827,6 +8830,93 @@ begin
Result:=FindExprTypeAsString(ExprType,TermPos.StartPos,Params);
end;
function TFindDeclarationTool.FindForInTypeAsString(TermPos: TAtomPosition;
CursorNode: TCodeTreeNode; Params: TFindDeclarationParams; out
ExprType: TExpressionType): string;
procedure RaiseTermHasNoIterator;
begin
if TermPos.StartPos<1 then
TermPos.StartPos:=1;
MoveCursorToCleanPos(TermPos.StartPos);
RaiseException('Can not find an enumerator for '''+TrimCodeSpace(GetAtom(TermPos))+'''');
end;
begin
ExprType:=CleanExpressionType;
Params.ContextNode:=CursorNode;
Params.Flags:=[fdfSearchInParentNodes,fdfSearchInAncestors,
fdfTopLvlResolving,fdfFunctionResult];
ExprType:=FindExpressionResultType(Params,TermPos.StartPos,TermPos.EndPos);
{$IFDEF ShowExprEval}
DebugLn('TFindDeclarationTool.FindForInTypeAsString TermType=',
ExprTypeToString(ExprType));
{$ENDIF}
case ExprType.Desc of
xtContext:
begin
// ToDo
RaiseTermHasNoIterator;
end;
xtNone,
xtChar,
xtWideChar,
xtReal,
xtSingle,
xtDouble,
xtExtended,
xtCurrency,
xtComp,
xtInt64,
xtCardinal,
xtQWord,
xtBoolean,
xtByteBool,
xtLongBool,
xtPointer,
xtFile,
xtText,
xtConstOrdInteger,
xtConstReal,
xtConstBoolean,
xtLongint,
xtLongWord,
xtWord,
xtSmallInt,
xtShortInt,
xtByte,
xtCompilerFunc,
xtVariant,
xtNil:
RaiseTermHasNoIterator;
xtString,
xtAnsiString,
xtShortString,
xtPChar,
xtConstString:
begin
ExprType.Desc:=xtChar;
Result:=ExpressionTypeDescNames[ExprType.Desc];
end;
xtWideString,
xtUnicodeString:
begin
ExprType.Desc:=xtWideChar;
Result:=ExpressionTypeDescNames[ExprType.Desc];
end;
xtConstSet:
RaiseTermHasNoIterator; // ToDo
else
DebugLn('TFindDeclarationTool.FindForInTypeAsString ExprType=',
ExprTypeToString(ExprType));
RaiseTermHasNoIterator;
end;
{$IFDEF ShowExprEval}
DebugLn('TFindDeclarationTool.FindForInTypeAsString Result=',Result);
{$ENDIF}
end;
function TFindDeclarationTool.IsTermEdgedBracket(TermPos: TAtomPosition; out
EdgedBracketsStartPos: integer): boolean;
{ allowed:
@ -8890,6 +8980,7 @@ end;
function TFindDeclarationTool.IsTermNamedPointer(TermPos: TAtomPosition; out
ExprType: TExpressionType): boolean;
// check if TermPos is @Name and a pointer (= ^Name) can be found
var
SubExprType: TExpressionType;
Node: TCodeTreeNode;