【问题标题】:Is there a way to keep variable values when executing a DWScript twice?有没有办法在执行 DWScript 两次时保留变量值?
【发布时间】:2012-06-09 03:19:25
【问题描述】:

我正在开发的应用程序允许将脚本 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。在内部,第一个脚本 sn-p 被编译和执行。比下一个是 RecompiledInContext 并执行等等。在 sn-p 中声明的函数/变量/等在所有以后的 sn-ps 中都可用。 然而,变量值在 sn-ps 之间丢失。例如:

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;

【问题讨论】:

  • 呃...交换脚本命令会中断执行。似乎使此功能起作用的唯一方法是使用调试器深入挖掘库。祝您使用 DWSCript 好运! :)

标签: delphi dwscript


【解决方案1】:

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

【讨论】:

  • 这不可靠。我刚刚尝试了以下代码,它导致了 AV 错误。 (必须将其发布为答案,因为不适合作为评论)
  • @RM 你有哪个 Delphi 版本?
  • Delphi XE2 Update 4(包括热修复)+最新的DWScript源码
  • @RM。最新的 DWScript 意味着 2.3(不稳定)?
【解决方案2】:

问题是当 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();

编辑:这已由 r1513 在DWScript SVN 中修复。

【讨论】:

  • 嗨,Eric,使用最新的源代码可以正常工作。这太棒了!感谢您解决此问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-17
  • 2017-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
相关资源
最近更新 更多