开发者

How to obtain the line numbers of executable lines from DWScript context map or symbol table

开发者 https://www.devze.com 2023-04-01 00:32 出处:网络
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

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)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号