简体   繁体   English

是否可以使用DWScript创建Read-eval-print循环(REPL)?

[英]Is it possible to create a Read–eval–print loop (REPL) using DWScript?

I am trying to create a Read–eval–print loop (REPL) with DWScript and I'm not sure this is possible. 我正在尝试使用DWScript创建一个Read-eval-print循环(REPL),我不确定这是否可行。

Based on the name, I assumed that RecompileInContext would work fine in that context but I am experiencing some limitations: 根据名称,我假设RecompileInContext在该上下文中可以正常工作,但我遇到了一些限制:

  • A buggy line is forever included in the program: future run will always fail due to that line 程序中永远包含一个有缺陷的行:未来的运行将始终因该行而失败
  • I didn't find a way to output the value of a variable simply by typing it. 我没有找到一种方法来输入变量的值,只需输入它。 For example when typing var test = "content"; 例如,当键入var test = "content"; then test , content should be displayed. 然后test ,应显示content As far as I can tell, using print or println can't work as they will be executed at each run 据我所知,使用printprintln无法工作,因为它们将在每次运行时执行

So my question is: Is it possible to create a REPL using DWScript ? 所以我的问题是:是否可以使用DWScript创建REPL?

Here is what I've got so far: 这是我到目前为止所得到的:

program DwsRepl;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  dwsComp,
  dwsCompiler,
  dwsExprs;

var
  oCompiler: TDelphiWebScript;
  oProgram: IdwsProgram;
  oExecution: IdwsProgramExecution;
  sInput: string;
begin
  try
    oCompiler := TDelphiWebScript.Create(nil);
    try
      oProgram := oCompiler.Compile('', 'ReplScript');
      oExecution := oProgram.BeginNewExecution;
      try
        while True do
        begin
          Write('> ');
          // Read user input
          Readln(sInput);
          // Exit if needed
          if sInput = '' then Break;
          // Compile
          oCompiler.RecompileInContext(oProgram, sInput);
          if not oProgram.Msgs.HasErrors then
          begin
            oExecution.RunProgram(0);
            // Output
            if not oExecution.Msgs.HasErrors then
             Writeln(oExecution.Result.ToString)
            else
             Writeln('EXECUTION ERROR: ' + oExecution.Msgs.AsInfo);
          end
          else
           Writeln('COMPILE ERROR: ' + oProgram.Msgs.AsInfo);
        end;
      finally
        oExecution.EndProgram;
      end;
    finally
      oCompiler.Free();
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

You can use TdwsCompiler.Evaluate to compile a snippet to an IdwsEvaluateExpr, it is then possible to evaluate the contained expression to a string with yourEvaluateExpr.Expression.EvalAsString 您可以使用TdwsCompiler.Evaluate将代码段编译为IdwsEvaluateExpr,然后可以使用yourEvaluateExpr.Expression.EvalAsString将包含的表达式计算为字符串。

The above is the typical mechanism to use for debug evaluations, expression watches or conditional breakpoints (though not always evaluated as string, an expression can return an object, an array, etc. or can hold a statement that returns nothing). 以上是用于调试评估,表达式监视或条件断点的典型机制(虽然并不总是作为字符串求值,但表达式可以返回对象,数组等,或者可以保存不返回任何内容的语句)。

RecompileInContext will keep the declarations, but throw away the "main" code, so bugs in the main code will not affect future runs, but if you declare a faulty type for a variable, or a faulty function implementation, it will stay there in the script context. RecompileInContext将保留声明,但丢弃“主”代码,因此主代码中的错误不会影响将来的运行,但如果您为变量声明了错误类型,或者错误的函数实现,它将保留在脚本上下文。

However the message list is not cleared automatically, you have to clear it yourself (originally RecompileInContext was intended to handle small script snippets in a larger source, so keeping as many errors as possible in the message list was the desired behavior, so that a correct last script would not "erase" the errors of an incorrect first script) 但是,消息列表不会自动清除,您必须自己清除它(最初RecompileInContext旨在处理较大源中的小脚本片段,因此在消息列表中保留尽可能多的错误是所需的行为,因此正确最后一个脚本不会“擦除”错误的第一个脚本的错误)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM