9

私が取り組んでいるアプリケーションでは、スクリプト シンペットをドキュメントに埋め込むことができます。例えば:

SomeText
<* PrintLn("This line is generated by a script"); *>
Some other text
<* PrintLn("This line is generated by a script, too"); *>
Some more lines

結果

SomeText
This line is generated by a script
Some other text
This line is generated by a script, too
Some more lines

DWScript を使用しています。内部的には、最初のスクリプト スニペットがコンパイルおよび実行されます。次は RecompiledInContext であり、実行されます。スニペットで宣言された関数/変数/etc は、それ以降のすべてのスニペットで使用可能になります。ただし、変数値はスニペット間で失われます。例えば:

SomeText
<* var x: Integer = 5; *>
Some other text
<* PrintLn(x); *>
Some more lines

ドキュメントの生成後:

SomeText
Some other text
0  <-- I would like this to be 5
Some more lines

この問題を説明するサンプル アプリケーションを次に示します。

program POC.Variable;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  dwsExprs,
  dwsComp,
  dwsCompiler; 

var
  FDelphiWebScript: TDelphiWebScript;
  FProgram: IdwsProgram;
  FExecutionResult: IdwsProgramExecution;

begin
  FDelphiWebScript := TDelphiWebScript.Create(nil);
  try
    FProgram := FDelphiWebScript.Compile('var x: Integer = 2;');
    FProgram.Execute;

    FDelphiWebScript.RecompileInContext(FProgram, 'PrintLn(x);');

    FExecutionResult := FProgram.Execute;
    // The next line fails, Result[1] is '0'
    Assert(FExecutionResult.Result.ToString[1] = '2');
  finally
    FDelphiWebScript.Free;
  end
end.

実行間で変数値を「転送」または「保持」する方法はありますか?

これは、機能しないアンドリューの回答の更新されたコードです。

begin
  FDelphiWebScript := TDelphiWebScript.Create(nil);
  try
    FProgram := FDelphiWebScript.Compile('PrintLn("Hello");');

    FExecution:= FProgram.BeginNewExecution();

    FDelphiWebScript.RecompileInContext(FProgram, 'var x: Integer;');
    FExecution.RunProgram(0);
    WriteLn('Compile Result:');
    WriteLn(FExecution.Result.ToString);

    FDelphiWebScript.RecompileInContext(FProgram, 'x := 2; PrintLn(x);');
    FExecution.RunProgram(0); // <-- Access violation
    WriteLn('Compile Result:');
    WriteLn(FExecution.Result.ToString);

    FExecution.EndProgram();
    ReadLn;
  finally
    FDelphiWebScript.Free;
  end
end;
4

2 に答える 2

5

BeginNewExecution代わりに/ RunProgram/ブロックを使用してみることができますEndProgram(DWScript 2.2 でテスト済み):

begin
  FDelphiWebScript := TDelphiWebScript.Create(nil);
  try
    FProgram := FDelphiWebScript.Compile('var x: Integer;');

    FExecution:= FProgram.BeginNewExecution();

    FDelphiWebScript.RecompileInContext(FProgram, 'x := 2; PrintLn(x);');
    FExecution.RunProgram(0);
    WriteLn('Compile Result:');
    WriteLn(FExecution.Result.ToString);

    FDelphiWebScript.RecompileInContext(FProgram, 'x := x + 3; PrintLn(x);');
    FExecution.RunProgram(0);
    WriteLn('Recompile Result: ');
    WriteLn(FExecution.Result.ToString);

    FExecution.EndProgram();

    ReadLn;
  finally
    FDelphiWebScript.Free;
  end
end.
于 2012-06-09T07:07:35.137 に答える
1

問題は、RecompileInContext() が新しいグローバル変数を追加するときに、スペースの割り当てが BeginNewExecution によって実行されるため、スペースが割り当てられないことですが、変数が既に存在する場合、または新しい変数が関数内に追加された場合は機能するはずです。グローバル変数ではなく、ローカル変数です)。

したがって、「更新されたコード」を次のように変更すると、機能します

FProgram := DelphiWebScript1.Compile( 'PrintLn("Hello");'
                                     +'var x: Integer;');

FExecution:= FProgram.BeginNewExecution();

FExecution.RunProgram(0);
SynEdit1.Lines.Add('Compile Result:');
SynEdit1.Lines.Add(FExecution.Result.ToString);

DelphiWebScript1.RecompileInContext(FProgram, 'x := 2; PrintLn(x);');
FExecution.RunProgram(0); // <-- Access violation
SynEdit1.Lines.Add('Compile Result:');
SynEdit1.Lines.Add(FExecution.Result.ToString);

FExecution.EndProgram();

編集:これはDWScript SVNの r1513 によって修正されました。

于 2012-06-20T10:09:12.157 に答える