Как получить номера строк исполняемых строк из контекстной карты DWScript или таблицы символов - PullRequest
2 голосов
/ 01 сентября 2011

Я пишу IDE для использования с Delphi DWScript и теперь у меня есть простой отлаживаемый скрипт. Теперь я хочу выделить исполняемые строки в моем источнике (например, синие точки слева от источника Delphi). Копая примеры / информацию, я вижу, что есть программа SymbolDictionary, где я могу вызвать FindSymbolUsage (suReference) - это, кажется, дает мне позиции символов «на которые ссылаются», и я думаю, что я мог бы вызвать это снова с « suImplementation ', чтобы получить строки, где есть назначение. Это заставило меня понять, что я могу понять, какова структура и назначение ContextMap и SymbolDictionary. У кого-нибудь есть пример перечисления номеров исполняемых строк скрипта?

Мой молодой код воспроизведен ниже и ожидает критического анализа :-) Спасибо

  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;

1 Ответ

3 голосов
/ 02 сентября 2011

TdwsSymbolDictionary служит для другой цели, главным образом зная, где (если) символ объявлен или используется, а также облегчает такие вещи, как рефакторинг переименования (см. http://delphitools.info/2011/02/19/spotlight-on-tsymboldictionary/).

TdwsSourceContextMap служит для того, чтобы узнать, где в исходном коде находятся «блоки» кода (например, где объявление класса заканчивается и заканчивается, где начинается и заканчивается реализация функции и т. Д.), И то, и другое полезно для «перехода» на позицию в коде или узнать, где находится курсор в терминах символов.

То, что вы ищете, это еще одна информация, это то, что строки соответствуют скомпилированным выражениям. Для этого вам нужно посмотреть, что скомпилировано, TExprBase.SubExpr / SubExprCount - ваши рабочие лошадки или служебная функция, которая их оборачивает RecursiveEnumerateSubExprs. С помощью этой функции вы можете просматривать все выражения в вашей программе, начиная с TdwsProgram.Expr и TdwsProgram.InitExpr (вы можете привести IdwsProgram к TdwsProgram, чтобы получить эти свойства).

Здесь вы можете иметь точки останова.

В качестве иллюстрации предположим, что у вас есть

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;

Тогда, если я не ошибаюсь (делаю это неожиданно):

  • В словаре символов будет указано объявление "Dummy" в 1, a использование «Integer» в 1 и 2, объявление «i» в 2, использование «i» в 4, 5 и 6.

  • В контекстной карте будет блок для функции, основной блок и цикл while.

  • Строки со скомпилированными выражениями будут 2 (.InitExpr) и 4, 5, 6 & 7 (.Expr)

...