我正在处理的应用程序允许将脚本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
Run Code Online (Sandbox Code Playgroud)
结果
SomeText
This line is generated by a script
Some other text
This line is generated by a script, too
Some more lines
Run Code Online (Sandbox Code Playgroud)
我正在使用DWScript.在内部编译和执行第一个脚本片段.比下一个是RecompiledInContext并执行等等.在片段中声明的函数/变量/ etc在所有后续片段中都可用.但是,片段之间的变量值会丢失.例如:
SomeText
<* var x: Integer = 5; *>
Some other text
<* PrintLn(x); *>
Some more lines
Run Code Online (Sandbox Code Playgroud)
生成文档后:
SomeText
Some other text
0 <-- I would like this to be 5
Some more lines
Run Code Online (Sandbox Code Playgroud)
这是一个说明问题的示例应用程序:
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.
Run Code Online (Sandbox Code Playgroud)
有没有办法在执行之间"转移"或"保留"变量值?
这是Andrew的答案的更新代码,它不起作用:
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;
Run Code Online (Sandbox Code Playgroud)
您可以尝试使用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.
Run Code Online (Sandbox Code Playgroud)
问题是,当 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();
Run Code Online (Sandbox Code Playgroud)
编辑:现在已由DWScript SVN中的 r1513 修复。