Recent

Author Topic: Implementing feature like javascript eval  (Read 400 times)

egsuh

  • Hero Member
  • *****
  • Posts: 1520
Implementing feature like javascript eval
« on: September 29, 2024, 12:36:09 am »
Is there any easy way to implement function to evaluate user-defined expression, like

  25 in [4,6,22..29]      //  <== this will be given from TEdit or by program, while running a program.

I'm looking at Pascal Script. Is there any way to get the value of TPSScript's internal variables from wrapping application? I.E. the values of ai and bi in the last example of following page.

https://wiki.lazarus.freepascal.org/Pascal_Script_Examples

Of course I can put them as TLabel.caption or TEdit.text of wrapping applition and read them, but are there any direct way?

Fibonacci

  • Hero Member
  • *****
  • Posts: 646
  • Internal Error Hunter
Re: Implementing feature like javascript eval
« Reply #1 on: September 29, 2024, 03:14:03 am »
Here. I've cleaned up a few things here and there in my old snippet, so you will have a better understanding of this mess. As you can see not everthing is working like in the native FPC (this range thing for example) :)

Code: Pascal  [Select][+][-]
  1. program pascalscriptdemo;
  2.  
  3. uses uPSCompiler, uPSUtils, uPSComponent;
  4.  
  5. type
  6.   tx = class
  7.     ps: TPSScript;
  8.     constructor Create;
  9.     procedure Free;
  10.     procedure oncompile(Sender: TPSScript);
  11.     procedure onexecute(Sender: TPSScript);
  12.     procedure eval(expr: string);
  13.   end;
  14.  
  15. var
  16.   myvar: integer;
  17.  
  18. procedure myprint(s: string);
  19. begin
  20.   writeln('print = ', s);
  21. end;
  22.  
  23. procedure myprintint(i: integer);
  24. begin
  25.   writeln('printint = ', i);
  26. end;
  27.  
  28. procedure myeval(b: boolean);
  29. begin
  30.   writeln(b);
  31. end;
  32.  
  33. constructor tx.Create;
  34. begin
  35.   ps := TPSScript.Create(nil);
  36.   ps.OnCompile := @oncompile;
  37.   ps.OnExecute := @onexecute;
  38. end;
  39.  
  40. procedure tx.Free;
  41. begin
  42.   ps.Free;
  43. end;
  44.  
  45. procedure tx.oncompile(Sender: TPSScript);
  46. begin
  47.   Sender.AddFunction(@myeval, 'procedure eval(b: boolean);');
  48.   Sender.AddFunction(@myprint, 'procedure print(s: string);');
  49.   Sender.AddFunction(@myprintint, 'procedure printint(i: integer);');
  50.   Sender.AddRegisteredPTRVariable('myvar', 'Longint')
  51. end;
  52.  
  53. procedure tx.onexecute(Sender: TPSScript);
  54. begin
  55.   Sender.SetPointerToData('myvar', @myvar, ps.FindBaseType(bts32));
  56. end;
  57.  
  58. procedure tx.eval(expr: string);
  59. begin
  60.   write(expr:30, ' = ');
  61.   ps.Script.Text := 'begin eval('+expr+'); end.';
  62.  
  63.   if not ps.Compile then
  64.     writeln('compile failed')
  65.   else if not ps.Execute then
  66.     writeln('execute failed');
  67. end;
  68.  
  69. var
  70.   x: tx;
  71.  
  72. begin
  73.   x := tx.Create;
  74.  
  75.   // evals
  76.   x.eval('1 = 1');
  77.   x.eval('''test'' = ''test''');
  78.   x.eval('2 in [1, 2, 3]');
  79.   x.eval('2 in [1, 3]');
  80.   x.eval('2 in [1..3]');
  81.   x.eval('10 in [1..100]');
  82.   x.eval('3 in [1, 2, 4..10]');
  83.   writeln;
  84.  
  85.   // read "myvar" from pascalscript
  86.   x.ps.Script.Text := 'begin myvar := 1337; end.';
  87.  
  88.   if not x.ps.Compile then begin
  89.     writeln('compile failed');
  90.     readln; exit;
  91.   end;
  92.  
  93.   if not x.ps.Execute then begin
  94.     writeln('execute failed');
  95.     readln; exit;
  96.   end;
  97.  
  98.   // write it out
  99.   writeln('myvar = ', myvar);
  100.  
  101.   // change it
  102.   myvar := 1234;
  103.  
  104.   // print it with pascalscript, its just a pointer so value is the same here and in PS
  105.   x.ps.Script.Text := 'begin printint(myvar) end.';
  106.   x.ps.Compile;
  107.   x.ps.Execute;
  108.   writeln;
  109.  
  110.   x.Free;
  111.  
  112.   writeln('end of demo');
  113.   readln;
  114. end.

Code: Pascal  [Select][+][-]
  1.                          1 = 1 = TRUE
  2.                'test' = 'test' = TRUE
  3.                 2 in [1, 2, 3] = TRUE
  4.                    2 in [1, 3] = FALSE
  5.                    2 in [1..3] = compile failed
  6.    10 in [1..5, 6..10, 11..15] = compile failed
  7.             3 in [1, 2, 4..10] = compile failed
  8.  
  9. myvar = 1337
  10. printint = 1234
« Last Edit: September 29, 2024, 03:15:49 am by Fibonacci »

egsuh

  • Hero Member
  • *****
  • Posts: 1520
Re: Implementing feature like javascript eval
« Reply #2 on: September 29, 2024, 07:02:02 am »
Hi Fibonacci,

Really thank you for your example. I successfully implemented your example in my GUI application. Now I have a better image of PascalScript.

The key seems :

Code: Pascal  [Select][+][-]
  1. var
  2.     myvar: integer;      
  3.  
  4. procedure TForm1.psComple(Sender: TPSScript);
  5. begin
  6.    Sender.AddRegisteredPTRVariable('myvar', 'Longint')
  7. end;                  
  8.  
  9. procedure TForm1.psExecute(Sender: TPSScript);
  10. begin
  11.    Sender.SetPointerToData('myvar', @myvar, Sender.FindBaseType(bts32));
  12. end;
  13.  
  14. procedure TForm1.Button1Click(Sender: TObject);
  15. begin
  16.    ps.Script.Text := 'begin myvar := 4 + 2 * 567; end.';   // <== I can write expression here
  17.  
  18.    if not ps.Compile then begin
  19.        ShowMessage('compile failed');
  20.        exit;
  21.    end;
  22.  
  23.    if not ps.Execute then begin
  24.        ShowMessage ('execute failed');
  25.        exit;
  26.    end;
  27.  
  28.    ShowMessage(Format('myvar = %d', [myvar]));  // <-- here I can read the value directly.
  29. end;
  30.  

I think this example should be given at the beginning of Pascal Script, because what I expect is running custom-defined function/calculation etc. at runtime, not running already-compiled code (from main program)  within the Script.

 

TinyPortal © 2005-2018