有没有办法在执行两次 DWScript 时保留变量值



我正在处理的应用程序允许将脚本 sinppets 嵌入到文档中。例如:

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。在内部编译和执行第一个脚本片段。然后下一个是重新编译InContext并执行等等。在代码段中声明的函数/变量/等在所有以后的代码片段中都可用。但是,变量值在代码段之间丢失。例如:

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;

您可以尝试使用 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.

问题是当 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修复。

最新更新