2012-06-09 8 views
9

L'applicazione su cui sto lavorando consente di incorporare sinppets di script in un documento. Per esempio:C'è un modo per mantenere i valori delle variabili quando si esegue un DWScript due volte?

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

Risultati

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

Sto usando DWScript. Internamente il primo snippet di script è compilato & eseguito. Il successivo è RecompiledInContext ed eseguito e così via. Una funzione/variabile/etc dichiarata in uno snippet diventa disponibile in tutti i frammenti successivi. Tuttavia i valori delle variabili sono persi tra i frammenti. Per esempio:

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

Dopo aver generato il documento:

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

Qui è un'applicazione di esempio che illustra il problema:

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. 

C'è un modo per "trasferimento" o "tenere "i valori variabili tra le esecuzioni?

Ecco un codice aggiornato di risposta di Andrea che non funziona:

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; 
+0

Urgh ... Lo scambio dei comandi di script interrompe l'esecuzione. Sembra che l'unico modo per far funzionare questa funzionalità sia scavare in profondità nella libreria con il debugger. Buona fortuna per te con DWSCript! :) – Andrew

risposta

1

Il problema è che quando RecompileInContext() aggiunge nuove variabili globali, non hanno spazio allocato, poiché l'allocazione dello spazio viene eseguita da BeginNewExecution, ma dovrebbe funzionare se le variabili preesistono o se sono presenti nuove variabili aggiunti all'interno di una funzione, quindi sono vars locali, piuttosto che globali).

Quindi, se si modifica il "codice aggiornato" per qualcosa di simile, funzionerà

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(); 

Edit: questo come ora è stato risolto r1513 nel DWScript SVN.

+0

Ciao Eric, funziona come previsto con l'ultima fonte. Questo e spettacolare! Grazie per aver risolto questo. –

5

si può provare ad usare BeginNewExecution/RunProgram/EndProgram blocco invece (testato su 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. 
+0

Questo non è affidabile. Ho appena provato il seguente codice e si è verificato un errore AV. (Devo postarlo come risposta dato che non si adatta come commento) –

+0

@ RM quale versione di Delphi hai? – Andrew

+0

Delphi XE2 Update 4 (inclusa hotfix) + ultima fonte DWScript –