nielsAD / lape

Scripting engine with Pascal-like syntax for FPC and Delphi
112 stars 26 forks source link

Questions #86

Closed 3FLLC closed 1 year ago

3FLLC commented 8 years ago

@nielsAD Okay, I found my memory leak - was in the new namespaces code I added. As I am migrating code, I have a couple questions -

what do these do? autoproperties constaddress coperators

something I touched has broken accessing AnsiString[index], this was working until I started synchronizing lpcompiler lso options - which makes no sense to me: ERROR: Cannot invoke identifier at line 81, column 11 in file "tests/Arithmetics_String.lap

3FLLC commented 8 years ago
 const
    _a:string='abc';

 var
    a:string;

 begin
    a:=_a;
    writeln(a);
    writeln(length(a));
    writeln(_a);
    writeln(_a[1]);
    writeln(a[1]);
 end.

last writeln fails - where should I look?

@nielsAD Cannot invoke identifier at line 13, column 13 in file "t.p"

Once I have a ballpark of where to look, I can diff the source. oddly, my old code runs it perfectly, so this is where something I used to do, does not marry-up with the way it should be done now.

nielsAD commented 8 years ago

See tests for (1) autoproperties, (2) constaddress (allows pointers to constants), (3) compound operators.

As for the index operation; probably the result type is lost somewhere.

nielsAD commented 8 years ago

The code you pasted above works for me (RangeChecking is turned on by default). Maybe check if you made any modifications to handling lcoRangeCheck.

3FLLC commented 8 years ago

works:

 {$R-}
 const
    _a:string='abc';

var
   a:string;

begin
   a:=_a;
   writeln(a);
   writeln(length(a));
   writeln(_a);
   writeln(_a[1]);
   writeln(a[1]);
end.

however, what if I need to turn off range checking for one routine and then back on for another? In my tests, I see compiler options are global not local to the routines. e.g. the last state of $R is the state used for the whole run-time. Is this fixable?

3FLLC commented 8 years ago

@nielsAD MP-Lape is now manually synchronized all .pas files.

To-Do:

  1. I am working on line by line tester for lpparser/lpcompiler script.
  2. I still have to move some code around to make LAPE mutli-threaded friendly for my socket server. (e.g. lpparser:
 initialization
  Lape_InitKeywordsCache();
  {$IFDEF LoadDefaultFormatSettings}
  GetLocaleFormatSettings(0, FormatSettings);
  {$ENDIF}
finalization
  Lape_ClearKeywordsCache();

making it thread safe).

  1. then synchronizing all my docs to your docs/lape.rst file ;-)
slackydev commented 8 years ago

however, what if I need to turn off range checking for one routine and then back on for another? In my tests, I see compiler options are global not local to the routines. e.g. the last state of $R is the state used for the whole run-time. Is this fixable? - 3FLLC

The switch does not affect the whole script but only from the point where it's toggled, and until it's changed again, switches are parsed as we go.

This should display it:

var
  a:array of Int32;
begin
  {$R-}
  a[10]; //passes by

  {$R+}
  try
    a[10];  //raises
  except
    WriteLn 'raised';
  end;

  {$R-} //the rest of the code uses R- now.
  a[10]; //passes by
end.

so for your function, you enable it in the begining, and then disable it at the end.

3FLLC commented 8 years ago

Your are right, I introduced the bug :-(

fixing property Options:{...} read FOptions write FBaseOptions; (making it use SetOptions) ended breaking FOptions' scope. Undoing my "fix" and just applying "Compiler.Reset()" everywhere I need the change to happen pre Compiler.compile(...).

Thanks!!

3FLLC commented 8 years ago

Undid my setOptions() change to lpvartypes (compiler base), and I still get:

Compilation error: "Cannot invoke identifier at line 13, column 6

3FLLC commented 8 years ago

@WarPie - thanks for proven it did work - after doing a line by line comparison - I finally found, _RangeCheck was my issue. It was not migrated into MP2, as I thought it was like Between(..) or inRange(...) from my Math RTL. Once I found vartypes_array uses _RangeCheck I was able to resolve it. PHEW!

3FLLC commented 8 years ago

@nielsAD new question - I am porting over some UUID/MSGID code from C to MP.... how hard would it be for us to implement "bit" support in records?

  struct
  {
    unsigned TaskNumber:5;
    unsigned DayOfYear:9;
    unsigned Year:2;            /* Enough to meet the three-year rule */
    unsigned Secs30:12;
    unsigned Count:4;
  } x; // sizeof() == 32

Or is there a way to have LA-PE align to this structure?

nielsAD commented 8 years ago

The best way to work around this is by just using a 32 bit integer type and wrapping the C fields into getters/setters.

Adding this to Lape is possible but difficult, because there's nothing like it at the moment. Currently, there's no read evaluation, which would be needed for something like this. Adding that is non-trivial, but would also be beneficial for properties.

3FLLC commented 8 years ago

@nielsAD a while back you helped me implement this, but I cannot find my notes.

  Write(#27+']2;LiveMenu - Telnet Edition'+#7);
  ctlcms.init(nil);
  ctlcms.setFilename(rootpath+'control.cms');
  ctlcms.setFirstlineIsSchema(false);
  ctlcms.open();
  ds:=ctlcms;
  df:=ds.FieldByName('Field1');
  _Version:=df.getAsFloat;
  ctlcms.free;

Note I have to store TField to DF then I can work with DF.getAsFloat. You had pointed me to the piece of code to understand ds.FieldByName("Field1").getAsFloat --- right now if I run that statement I get "Variable expected at line..." so I have to store the object to variable, then reference that variable/object to get to it's methods. ... do you recall what I need to expand out?? (I still have my pre-LAPE-MERGE code, so I will be able to cut-n-paste my patch, hopefully).

nielsAD commented 8 years ago

You might have to work with constref or static keywords as in tests/Method_OfType.lap.

3FLLC commented 8 years ago

Actually last time, you had me work with the internal routine that handled "dot", I just don't remember it's name to go back and find how I fixed it.

3FLLC commented 8 years ago

@nielsAD could we support code like:

{$DEFINE BURGER}

{$IFDEF HOTDOG OR BURGER}
   !Error
{$ENDIF}

I am porting a lot of C code over, and I run into code like:

if defined(WITH_ZLIB) || defined(WITH_BZLIB2)

and I don't want to write the {$IFDEF} code twice, nor write:

{$IFDEF WITH_ZLIB}
   {$IFDEF WITH_BZLIB2}
      {$DEFINE WITH_ZLIB_BZLIB2}

etc. The goal is to keep the code as close to original as possible. But, I am not sure what it would take to add an evaluation for the IFnDEF logic parser.

nielsAD commented 8 years ago

I'm not sure what we discussed last time regarding fields. You might be able to find it in a mail?

$IF conditionals shouldn't be that difficult to add, as you can reuse the expression parser and constant evaluation parts. Adding declared and defined functions would be a bit more difficult.

3FLLC commented 7 years ago

@nielsAD what is the correct way to write this in a LAPE script?

type
   TDateTimeRec = record
   case TFieldType of
    ftDate: (
        Date: LongInt;
      );
    ftTime: (
        Time: LongInt;
      );
    ftDateTime: (
        DateTime: Double;
      );
end;

Is that where I would use a Union? And once coded, how would I access each element?

Thanks again! Ozz

nielsAD commented 7 years ago

Yes, that should be turned into a union.

type
   TDateTimeRec = union
     Date: LongInt;
     Time: LongInt;
     DateTime: Double;
  end;

var
  dt: TDateTimeRec;
begin
  dt.Date := 1;
  WriteLn(dt);
end;
3FLLC commented 7 years ago

Darn, error:

type TDateTimeRec = union Date: LongInt; Time: LongInt; DateTime: Double; end;

var dt: TDateTimeRec; begin dt.Date := 40000; dt.Time := 400; WriteLn(dt); end;

produces: {DATE = 400, TIME = 400, DATETIME = 1.97626258336499E-321}

Looks like union is expecting a single element period… does not understand the grouping of the bytes. Flipping them around JIC still same result: {DATETIME = 1.97626258336499E-321, DATE = 400, TIME = 400}

:-(

On Feb 22, 2017, at 10:07 AM, Niels AD notifications@github.com wrote:

Yes, that should be turned into a union.

type TDateTimeRec = union Date: LongInt; Time: LongInt; DateTime: Double; end;

var dt: TDateTimeRec; begin dt.Date := 1; WriteLn(dt); end; — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/nielsAD/lape/issues/86#issuecomment-281695449, or mute the thread https://github.com/notifications/unsubscribe-auth/AMlpMstYT4ps4ZcLEVgFBbJD5wf0hrYeks5rfE8igaJpZM4JP-9k.

nielsAD commented 7 years ago

I get the same result when running this with FreePascal... I'm not sure what you're expecting here?

3FLLC commented 7 years ago

union = 8 bytes in memory long = bytes 1 2 3 4 long = bytes 5 6 7 8 double = bytes 1..8

?

On Feb 22, 2017, at 11:50 AM, Niels AD notifications@github.com wrote:

I get the same result when running this with FreePascal... I'm not sure what you're expecting here?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/nielsAD/lape/issues/86#issuecomment-281728557, or mute the thread https://github.com/notifications/unsubscribe-auth/AMlpMohCkzd_Qmml93d95A9DQcV0evZEks5rfGdIgaJpZM4JP-9k.

nielsAD commented 7 years ago

Use a nested record:

type
   TDateTimeRec = union
     dt: record
       Date: LongInt;
       Time: LongInt;
     end;
     DateTime: Double;
  end;

var
  rec: TDateTimeRec;
begin
  rec.dt := [123, 456];
  WriteLn(rec);
end;
3FLLC commented 7 years ago

Thank you !! That is exactly what I was trying to port over… the pascal code was a record with a case inside it.. I will add this to my notes.

On Feb 22, 2017, at 12:03 PM, Niels AD notifications@github.com wrote:

Use a nested record:

type TDateTimeRec = union dt: record Date: LongInt; Time: LongInt; end; DateTime: Double; end;

var rec: TDateTimeRec; begin rec.dt := [123, 456]; WriteLn(rec); end; — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/nielsAD/lape/issues/86#issuecomment-281732659, or mute the thread https://github.com/notifications/unsubscribe-auth/AMlpMnx63TokdxUSmmtbkT3AZvip_fyYks5rfGpQgaJpZM4JP-9k.

3FLLC commented 7 years ago

@nielsAD

I am reviewing Turbo Pascal 7 manual, and came across this - where would be the "correct" place for me to implement this support:

(. .) "A left bracket ([) is equivalent to the character pair of left parenthesis and a period-(., and a right bracket (]) is equivalent to the character pair of a period and a right parenthesis-.)."

nielsAD commented 7 years ago

You can add this in lpparser.pas. Just have the parser return it as if it was a regular bracket.

3FLLC commented 6 years ago

@nielsAD

Hope all is well... is there a way to mimic OnShutdown, or ExitProc. http://putka.upm.si/langref/turboPascal/0681.html

When debugging a script that is running as an Apache Module, I would like to inject some code which documents which function, line, etc. was last running when the error occurred. And if possible, if FileHandle is Open, Close it - as sometimes the error is when I am saving to my log the web variables... without the close, it does not always write the last bit of text.

Ozz

nielsAD commented 6 years ago

A try..finally around your main function should work.

3FLLC commented 6 years ago

I tried, does not - it has to be something out in lpCompiler/lpInterpreter layer. As I need a way to PUSH into the AST code, Terminate - and it jump to the terminate code. When Apache says kill thread, I can trap the signal, however, the .run() is terminated. So, I was hoping for another way of letting the AST code "hey call this" that I could manually push. I have modified my run() that exception handling is shared with the script and the host - so I can always document the exception if from the script layer. However, sometimes the client disappears (hackers for example) before the script runs, and Apache signals me to abort right now.

If we can figure away to allow the host to do this, it may be useful when implementing a GUI/event driven wrapper... like handling windows events. I

3FLLC commented 6 years ago

@nielsAD the following code gives me Runtime error: "Invalid jump". Besides not know why, I would like to expand the error to explain what caused the invalid jump.

`uses Math;

const MaxProbability=1000;

type LootType=(Bloodstone, Copper, Emeraldite, Gold, Heronite, Platinum, Shadownite, Silver, Soranite, Umbrarite, Cobalt, Iron, Default); Looter = Class Probabilites:Array[0..12] of Longint; Choose:private function:LootType of object; AsString:private function(l:LootType):String of object; End;

function Looter.Choose:LootType; var Loop,randomValue:Word;

Begin randomValue:=Random(MaxProbability-1); Loop:=0; While Probabilites[Loop mod 12]<randomValue do begin Inc(Loop); End; Result:=LootType(Loop mod 12); End;

function Looter.AsString(l:LootType):String; Begin Case l of LootType(Bloodstone):Result:='Bloodstone'; LootType(Copper):Result:='Copper'; LootType(Emeraldite):Result:='Emeraldite'; LootType(Gold):Result:='Gold'; LootType(Heronite):Result:='Heronite'; LootType(Platinum):Result:='Platinum'; LootType(Shadownite):Result:='Shadownite'; LootType(Silver):Result:='Silver'; LootType(Soranite):Result:='Soranite'; LootType(Umbrarite):Result:='Umbrarite'; LootType(Cobalt):Result:='Cobalt'; LootType(Iron):Result:='Iron'; Else Result:='Iron'; End; End;

procedure Looter.Free; Begin End;

// Must be listed after all actual definitions // procedure Looter.Init; Begin Randomize; with Self do begin Probabilites[0]:=10; Probabilites[1]:=77; Probabilites[2]:=105; Probabilites[3]:=125; Probabilites[4]:=142; Probabilites[5]:=159; Probabilites[6]:=172; Probabilites[7]:=200; Probabilites[8]:=201; Probabilites[9]:=202; Probabilites[10]:=216; Probabilites[11]:=282; Probabilites[12]:=MaxProbability; TMethod(@Choose) := [@Looter.Choose, @Self]; TMethod(@Free) := [@Looter.Free, @Self]; End; End;

var loot:looter; n:longint;

begin loot.init; for n:=0 to 99 do Writeln(Loot.AsString(Loot.choose)); loot.free; end.`

3FLLC commented 6 years ago

@nielsAD

Finally found the Enum and Set issue - problem is lpvartypes_ord.pas ToString for Enum is using System.SizeInt, System.String, etc ... in my version - System is not defined yet... as I had started implementing NameSpace support (and never finished). Removed "System." in the few places you reference it - and viola, I can writeln Sets and Enumerations without issue.

This fix also allows that last game post to work when changing to Writeln(Loot.Choose);

Regards, Ozz

3FLLC commented 6 years ago

@nielsAD

I occasionally have this typo, which LAPE does not complain about....

Begin A:=30; B=3; Writeln(A*B); End;

The third line is not doing assignment, code runs, result is wrong. I did it again today, and wasted an hour to find that the issue was the script not the new plugin I was working on. Is it possible see if I am doing a comparison without being in if, while, etc.?

Ozz

3FLLC commented 6 years ago

@nielsAD - I am tracing through the code to get a better understanding (My Delphi won't trace the code, I had to setup Lazarus/GDB on Linux and it works - so first time in 4+ years I can trace whats going on - and hopefully I will find some of the bugs I have been reporting)... in the meantime, could you explain the usage(s) of these tokens?:

UnImplemented Experimental Deprecated ConstRef External Forward Overload Override Static

ollydev commented 6 years ago

@3FLLC The tests work fine, are you sure you're running these tests in lape?

etc..

ozznixon commented 5 years ago

lpeval_arr.inc @ 3290 fix... (sorry my code structure is not backward compatible to you, so I am manually sharing patches): Arr[op_IN][ltBoolean][ltLargeSet] := Arr[op_IN][ltUInt8][ltLargeSet]; //1180309 @ 3302: Arr[op_Plus][ltLargeSet][ltBoolean] := Arr[op_Plus][ltLargeSet][ltUInt8]; //1180309

lpeval_res.inc @ 3259: Arr[op_Plus][ltSmallSet][ltAnsiChar] := Arr[op_Plus][ltSmallSet][ltUInt8]; // 1180502 [ltSmallSet]; Arr[op_Plus][ltSmallSet][ltWideChar] := Arr[op_Plus][ltSmallSet][ltUInt16]; // 1180502 [ltSmallSet];

@ 3286: Arr[op_IN][ltBoolean][ltLargeSet] := Arr[op_IN][ltUInt8][ltLargeSet]; // 1180309 @ 3295: Arr[op_Plus][ltLargeSet][ltBoolean] := Arr[op_Plus][ltLargeSet][ltUInt8]; // 1180309 Arr[op_Plus][ltLargeSet][ltAnsiChar] := Arr[op_Plus][ltLargeSet][ltUInt8]; // 1180502 [ltLargeSet]; Arr[op_Plus][ltLargeSet][ltWideChar] := Arr[op_Plus][ltLargeSet][ltUInt16]; // 1180502 [ltLargeSet];

3FLLC commented 5 years ago

@nielsAD can you reproduce this?

program smalltest;
  var small: 10..50;
begin
  small := 100;
  writeln(small) { ??? }
end.

100 is out of range.

nielsAD commented 5 years ago

Range checks for subranges are not implemented.

3FLLC commented 4 years ago

@nielsAD

Where would be the best place to implement a quick SaveToFile of the script being compiled (after it has verified all syntax is correct and all methods exist) and after $include have pulled in all include source?

I basically want to save an all in one file - that I can then compress/encrypt - and reference it as a deployable snapshot of the source (like a form of compile, without compilation).

Thanks. Ozz

ollydev commented 4 years ago

@3FLLC

override TLapeCompiler.pushTokenizer, if not InPeek append the doc to your file.

3FLLC commented 2 years ago

@nielsAD

A while back you mentioned that I should try posting Bounty(s) for things I would like implemented. Was that here on github, or via another site?

Bounties on my whiteboard:

  1. Implement support for properties (setters, getters, and default). [Host Class and Script Class]
  2. Ability to support different grammars (parse different syntax/keywords - C++, VB, etc.)
3FLLC commented 2 years ago

3. Implement uses scriptname; - which also includes implement Unit keyword and structure.