How to obtain the line numbers of executable lines from DWScript context map or symbol table
I am writing an IDE to use with Delphi DWScript开发者_开发问答 and now have a simple debuggable script. I now want to highlight the executable lines in my source (like the blue dots at the left of the Delphi source). Digging for examples / information I see that there is a program 'SymbolDictionary' where I can call 'FindSymbolUsage( suReference)' - this seems to give me positions of symbols 'being referred to', and I guess I could call this again with 'suImplementation' to get the lines where there is an assignment. This has made me realise though that I could do with understanding what the structure and purpose of the ContextMap and the SymbolDictionary actually are. Does anyone have an example of listing the executable line numbers of the script?
My fledgling code is reproduced below and is awaiting critical analysis :-) Thanks
TExecutableLines = class( TObject )
constructor Create;
destructor Destroy; override;
PRIVATE
FLines : TBits;
function GetIsExecutable(ALineNumber: integer): boolean;
procedure SetIsExecutable(ALineNumber: integer; const Value: boolean);
PUBLIC
procedure Clear;
procedure Evaluate( AProgram : IdwsProgram; const AUnitName : string );
property IsExecutable[ALineNumber : integer] : boolean
read GetIsExecutable
write SetIsExecutable;
end;
{ TExecutableLines }
procedure TExecutableLines.Clear;
begin
FLines.Size := 0;
FLines.Size := 1024;
end;
constructor TExecutableLines.Create;
begin
inherited;
FLines := TBits.Create;
end;
destructor TExecutableLines.Destroy;
begin
FreeAndnil( FLines );
inherited;
end;
procedure TExecutableLines.Evaluate(AProgram: IdwsProgram; const AUnitName : string);
var
I : integer;
Pos : TSymbolPosition;
begin
Clear;
For I := 0 to AProgram.SymbolDictionary.Count-1 do
begin
Pos := AProgram.SymbolDictionary.FindSymbolPosList(
AProgram.SymbolDictionary[I].Symbol ).FindUsage( suReference);
if Pos <> nil then
If Pos.ScriptPos.IsMainModule then
IsExecutable[ Pos.ScriptPos.Line ] := True
else
if SameText( Pos.UnitName, AUnitName ) then
IsExecutable[ Pos.ScriptPos.Line ] := True
end;
end;
function TExecutableLines.GetIsExecutable(ALineNumber: integer): boolean;
begin
if ALineNumber = 0 then
raise Exception.Create('Lines numbers are 1..n' );
if ALineNumber < FLines.Size then
Result := FLines[ALineNumber]
else
Result := False;
end;
procedure TExecutableLines.SetIsExecutable(ALineNumber: integer;
const Value: boolean);
begin
if ALineNumber = 0 then
raise Exception.Create('Lines numbers are 1..n' );
if ALineNumber >= FLines.Size then
FLines.Size := ALineNumber+1;
FLines[ALineNumber] := Value;
end;
The TdwsSymbolDictionary serves a different purpose, mostly knowing where (if) a symbol is declared or used, as well as easing up things like rename refactoring (see http://delphitools.info/2011/02/19/spotlight-on-tsymboldictionary/).
The TdwsSourceContextMap serves to know where in the source code, code "blocks" are (f.i. where a class declaration starts and ends, where function implementation starts and ends, etc.), it's both useful to "jump" to a position in code, or to know where the cursor is in terms of symbols.
What you're after is yet another info, it's what lines correspond to compiled expressions. For that you need to look at what is compiled, TExprBase.SubExpr/SubExprCount are your workhorses, or the utility function that wraps them RecursiveEnumerateSubExprs. With that function you can look at all the expressions in your program, start from TdwsProgram.Expr and TdwsProgram.InitExpr (you can cast the IdwsProgram to a TdwsProgram to get at those properties).
These are where you can have breakpoints.
As an illustration, suppose you have
1. function Dummy : Integer;
2. var i : Integer;
3. begin
4. while i<10 do begin
5. Inc(i);
6. if i>5 then
7. break;
8. end;
9. end;
Then if I'm not mistaken (doing this out of the blue):
The symbol dictionary will list a declaration of "Dummy" at 1, a usage of "Integer" at 1 & 2, a declaration of "i" at 2, a usage of "i" at 4, 5 & 6.
The context map will have a block for the function, the main block and the while loop.
The lines with compiled expressions will be 2 (.InitExpr) and 4, 5, 6 & 7 (.Expr)
精彩评论