SRL Archive - Lape

Lape


nielsie95

2011-12-03 12:28:26

'Ello there, chaps!

For some time now, I have been working on an interpreter written in FPC/Delphi with a Pascal-like syntax (compatible with Pascal Script up to a certain degree). It is built with speed and cross-platform capability in mind. It is currently in an alpha stage and I am even able to compile a version of SRL with it. Although the name has been brought up a few times, I did not specifically write this for Simba and there is no guarantee I will finish it.

Features
  • Basetypes: Integers(Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64), Floats(Extended,Double,Single,Currency), Chars(Ansi,Wide), Strings(Short,Ansi,Wide,Unicode), Booleans(Boolean, ByteBool, WordBool, LongBool), Variants, arrays(static, dynamic), record, union, enums, sets, pointers, function pointers
  • Operations: := = <> > >= < <= @ ^ + - * / ** AND DIV OR XOR NOT SHL SHR
  • Language constructs: If, For, Case, Repeat, While, Try
  • Internal and external (overloaded) functions (with support for default params)
  • Internal/external variables and constants (every variable is represented exactly as how it would be by FPC/Delphi)
  • Support for local (nested) declarations. So function can have their own constants/types/variables/functions.
  • Support for multiple platforms (tested with Linux, Windows and Mac OS).
  • Fast(er) execution (it's a lot faster than Pascal Script)

It brings quite a few extra features over Pascal Script, which will be elaborated in the next post:
  • Defaults for parameters and variables
  • Constant records/arrays
  • Pointers
  • Overloaded functions
  • Ability to override (imported and script) functions
  • Else clause for for/while loops
  • Assignments are expressions, so you can chain them (a := b := 2)
  • Exit(Result)/Continue(Depth)/Break(Depth)
  • Unions (records with fields that point to the same place in memory)
  • Untyped parameters (note: this does not mean dynamic typing)
  • Option for loose syntax (var declarations in begin-end and expressions outside functions, etc.)
  • Type functions (including script declarations)

There are also things that are not supported (yet), such as classes and labels. Perhaps these things will come later. There are also a few incompatibilities. For example, PS supports Try-Finally-Except (in that specific order) and in PS you can assign to constant parameters.

If you would like to contribute, I would really appreciate it. Testing is very important (write/test a few simple scripts or benchmarks - preferably non RS). There's also a tutorial that Wizzup has been working on, which could use work (this would be awesome!). If you're interested, feel free to contact me.

There is a Simba branch which incorporates Lape as an interpreter (I also believe it's in the main Simba branch. I would really appreciate if you'd take it out for a spin and let me know what you think!

-Nielsie95

nielsie95

2011-12-03 12:28:37

Defaults for parameters and variables

procedure test(a: Integer = 1; b: string = 'a');
begin
WriteLn(a, ' -> ', b);
end;

begin
test;
test(,'hoi');
test(2);
end;

Constant records/arrays

type
TPoint = record
x, y: Integer;
end;

const
tp: TPoint = [1,2];

var
t: TPoint;
begin
t := tp;
t := [,2];
WriteLn(t, ' :: ', tp);
end;

Pointers

var
a: Integer;
b: ^Integer;
begin
a := 2;
b := @a;
b^ := 3;
WriteLn(a);
end;

Overloaded functions (this also works for imported functions)

procedure Hoi(Name: string); overload;
begin
WriteLn('Hoi ', Name);
end;

procedure Hoi; overload;
begin
Hoi('folks');
end;

begin
Hoi;
end;

Ability to override functions (this also works for script functions)

function IntToStr(i: Int64): string; override;
begin
Result := 'int ' + inherited;
end;

begin
Writeln(IntToStr(42));
end;

Else clause for for/while loops

begin
for 1 to -1 with 2 do
WriteLn('Looping')
else
WriteLn('No loop.. Aww!');

while False do
{nothing}
else
Writeln('No loop again. Jeez.');
end;

Assignments are expressions

var
a, b: Integer;
begin
a := b := 0;
a := 1 + (b := 2);
WriteLn('a: ', a, ' b: ', b);
end;

Exit(Result)/Continue(Depth)/Break(Depth)

function Test: Integer;
var
i: Integer;
begin
for i := 1 to 10 do
begin
WriteLn('i = ', i);
repeat
if (i < 3) then
Continue(2)
else
Break(2);
until False;

WriteLn('Out of the loop');
end;
Exit(-1);
end;

begin
Test;
end;

Unions

type
TRGBRecord = packed record
R, G, B: Byte;
end;
TRGB = union
Color: Integer;
RGB: TRGBRecord;
end;

var
c: TRGB;
begin
c.Color := 16777215 {clWhite};
WriteLn('R: ', c.RGB.R, ' G: ', c.RGB.G, ' B: ', c.RGB.B);
end;

Untyped parameters

procedure Untyped(const x);
begin
WriteLn(Integer(x));
end;

var
i = 1;
a = [1, 2, 3, 4];
begin
Untyped(i);
Untyped(a);
end;

Loose syntax

{$X+}

WriteLn('hoi!');

begin
var i = 0;
for var a := 0 to 2 do
i := i + a * 2;
WriteLn(a);
end;

Type functions

function Integer.Next: Integer;
begin
Result := Self + 1;
end;

begin
WriteLn(2.Next);
end;

Compiler directives
  • a, align - To determine how records are aligned
Used like {$Align 4} to align record fields on 4 bytes (this means a record with only a byte field is still 4 bytes long). This is added for compatibility with external records.
  • c, assertions - Compile assertions
  • b, booleval - Short circuit boolean evaluation
  • m, memoryinit - Initialize all variables to zero
  • x, extendedsyntax - Allow statements outside of regular blocks
  • f, autoinvoke - Allow invocation of methods without explicit parenthesis
  • s, scopedenums - Do not add enums to the scope (access through enum.field)

Used like {$B+}, {$B-} or {$B ON}, {$B OFF}.

Gu3st...

2011-12-03 12:31:57

Very nice! :)
Good job and congratulations on the SRL-Member's release ;)

noidea

2011-12-03 12:55:29

Ding dong the witch is dead!
Thanks for working on this. It'll be such a relief to get away from PS!

Wizzup?

2011-12-03 13:35:48

Great work. :)

nielsie95

2011-12-03 13:41:54

I've updated the second post with some examples.
Here's a little benchmark:


program new;
const
s = '123456789012345';
var
i, t: Integer;
e: Extended;
begin
t := GetTickCount;
for i := 1 to 2 * 1000 * 1000 do
e := 2 * (StrToFloat(s) * 0.5) - 1;
WriteLn(GetTickCount - t);
end.

Takes 13.5s in PS and 1.2s in Lape :)

i luffs yeww

2011-12-03 14:19:03

Any plans for ternary?

Hobbit

2011-12-03 14:19:46

Niels, you are a great human being :)

Markus

2011-12-03 14:25:06

From: nielsie95
Takes 13.5s in PS and 1.2s in Lape :)


Am I allowed to troll on the selectiveness of this benchmark? There are a few areas in Lape which are 100 times as slow as PS..

But still, it's a great job :p Performance issues will be fixed.

nielsie95

2011-12-03 14:52:26

From: Markus
Am I allowed to troll on the selectiveness of this benchmark? There are a few areas in Lape which are 100 times as slow as PS..

But still, it's a great job :p Performance issues will be fixed.

I've always stated that execution is way faster than with PS, I never spoke about compiling times ;)
Feel free to speed it up, though.

No plans for ternary, i luffs yew.

Kyle Undefined

2011-12-03 16:38:21

Leave it to Niels to come up with awesome stuff! :D

Sabzi

2011-12-30 12:28:36

I just read it again, so sexy!
Can't wait for certain things, pointers, function overload along with default parameters, some lose syntax!

How easily is this test-able? Both for helping and having fun purposes.

nielsie95

2011-12-30 12:34:26

Just download https://www.moparisthebest.com/jenkins/job/Simba_Lape/, set the interpreter (Script -> Interpreter -> Lape) and you're good to go. Pretty much everything is imported, except for classes.

Sabzi

2011-12-30 12:36:27

Thanks!
I will have an exam in 2 days, but after that I must have plenty of time to play with it. :stirthepot:

Daniel

2011-12-30 21:49:20

Just wondering Niels, but will we have class support? Or is that a feature you're thinking of adding, but it isn't on the ToDo list?

Cheers,
Daniel. :)

Echo_

2012-01-01 05:55:24

From: Daniel
Just wondering Niels, but will we have class support? Or is that a feature you're thinking of adding, but it isn't on the ToDo list?

Cheers,
Daniel. :)


That's what I'm wondering, also I don't know why you added unions rather than variant records.

Very nice job :)

nielsie95

2012-01-01 06:37:28

I didn't choose for variant records, because that syntax is pretty weird. The parsing for unions is the same as for records, which was easy :p

From: Daniel
Just wondering Niels, but will we have class support? Or is that a feature you're thinking of adding, but it isn't on the ToDo list?

Cheers,
Daniel. :)


Imported classes is on the to-do list, although the step to script classes is small.

Daniel

2012-01-01 11:47:56

From: nielsie95
I didn't chose for variant records, because that syntax is pretty weird. The parsing for unions is the same as for records, which was easy :p



Imported classes is on the to-do list, although the step to script classes is small.

Oh, okay :(

nielsie95

2012-01-03 11:15:22

Depending on what you want to do with classes, there are alternatives:


type
TPoint = record
x, y: Integer;
end;

procedure TPoint.New(ax, ay: Integer);
begin
x := ax;
y := ay;
end;

procedure TPoint.Swap;
var
c: Integer;
begin
c := x;
x := y;
y := c;
end;

function TPoint.Next: TPoint;
begin
Result := Self;
Inc(Result.x);
end;

var
t: TPoint;
begin
t.New(1, 2);
t.Swap;
WriteLn(t.Next.Next);
end;

You could simulate virtual methods, too :)

Dgby714

2012-01-03 11:19:14

No need to get Simba_Lape from jenkins. Lape has been in most of the resent releases of Simba.

Also, we could emulate some Form support as records. Also a wrapper needs to be wrote for SMART.

Wizzup?

2012-01-04 06:07:54

From: nielsie95
Just download https://www.moparisthebest.com/jenkins/job/Simba_Lape/, set the interpreter (Script -> Interpreter -> Lape) and you're good to go. Pretty much everything is imported, except for classes.


Simba_Lape hasn't been touched for 6 weeks, ever since it was merged into Simba_Master. There's no point to merge master into lape-integration since they would then hold exactly the same code… I could still do this if you want though. :p

nielsie95

2012-01-04 11:17:38

Alright, people can just use their current version then!

nielsie95

2012-01-24 09:33:34

I added support for labels. With some things commented out, I got Lape to compile SRL 5! :)

If you download the latest Simba and the latest SRL 5 from the lape_fixes branch, it should be able to compile! I even managed to log in a character and open the bank (that was all I tried)! Some parts in SRL will not work, because of the need for plugins or classes.

Daniel

2012-01-24 23:20:07

Hey Niels. Just wondering, what's the current status on plugin support? And if it's possible to export classes from plugins for use in Lape scripts?

If you can make that possible, I will love you forever :)

Regards,
Daniel. :)

nielsie95

2012-01-25 05:28:02

Plugins are possible, but functions will have to be exported using a proper "wrapper" format.
Classes should be possible when they're implemented, although I'm not sure why it isn't possible already with Pascal Script.

Daniel

2012-01-25 06:14:55

From: nielsie95
Plugins are possible, but functions will have to be exported using a proper "wrapper" format.

You mean like the standard, static, Delphi way of importing DLLs? If so, no problem.
From: nielsie95

Classes should be possible when they're implemented, although I'm not sure why it isn't possible already with Pascal Script.

It is, from various sources and tutorials on PascalScript regarding the subject, just the current plugin system Simba uses, it isn't possible.

Gu3st...

2012-01-25 06:18:54

How's multithreading coming along?

nielsie95

2012-01-25 07:56:56

From: Daniel
You mean like the standard, static, Delphi way of importing DLLs? If so, no problem.


procedure Lape_IntToStr(const Params: PParamArray; const Result: Pointer);
begin
string(Result^) := IntToStr(Integer(Params^[0]^));
end;
This is an example for IntToStr. Might look a bit intriguing, but it's actually pretty easy. This is needed to ensure it works on all platforms without the need for assembly.

From: Zyt3x
How's multithreading coming along?

Multithreading isn't really part of the engine. It could be implemented in several ways, just like it could be implemented in Pascal Script in several ways. I don't think it's that important, though. I'd rather get SRL working so that there's a chance people might actually test this ;)

Markus

2012-01-25 08:03:09

Is it possible to export those wrapper functions dynamically, or have you hardcoded all the functions in Lape?

nielsie95

2012-01-25 08:13:03

Not sure what you mean but you every function that Lape calls should be a wrapper function. You could dynamically load the wrappers, though.


type
MyProc = external procedure(w: Integer);
var
x: Pointer;
begin
x := @Wait;
MyProc(x)(10);
end;

The above will run. The variable x could be a pointer to any other (dynamically loaded) function.

Dgby714

2012-01-26 07:27:44

From: nielsie95
Not sure what you mean but you every function that Lape calls should be a wrapper function. You could dynamically load the wrappers, though.


type
MyProc = external procedure(w: Integer);
var
x: Pointer;
begin
x := @Wait;
MyProc(x)(10);
end;

The above will run. The variable x could be a pointer to any other (dynamically loaded) function.


He wants to know if there is a easier way to export functions to Lape.

Say a GenWrapper function?

function GenWrapper(…): Pointer; begin … end;
function a(): LongInt; begin Result := 42; end;

Addfunction('function a(): LongInt;', GenWrapper(@a));

nielsie95

2012-02-11 14:02:51

There are "easier" ways, but they have their downsides. I recommend to just import functions using the proper method.

On another note; I've just ran my first RS script using Lape!!

Wizzup?

2012-02-13 05:34:37

From: nielsie95
There are "easier" ways, but they have their downsides. I recommend to just import functions using the proper method.

On another note; I've just ran my first RS script using Lape!!


And it also run on Linux with Lape, mostly… :)

Markus

2012-02-13 17:17:14


program new;
begin
writeln(IntToHex(1234));
end.

Exception in Script: Don't know which overloaded method to call with params (Int32) at line 3, column 9

casting it to integer manually also does not work..\

edit: terminatescript also doesnt work lol

edit2:
program new;
var hoi : array [1..2] of integer;
begin
hoi[1234] := 4321;
end.
No bounds checking? ;)

Dgby714

2012-02-13 17:46:20

Can you add a way to call a script method from Simba? Like say RuntimeClass.CallProc? I know the runtime is currently just a procedure but It'd be nice.

Also can we get Pause, Resume, Stop, StepInto, StepOver?

Lastly a way to overload operators for types?

type
TTest: string

operator := (t: TTest) s: string; overload;
begin
s := something_to_do(t);
end;

Could also go the Python way and just look for something like __set__ and __get__? maybe even allow use to use __getitem__ and __setitem__?

var
Test: TTest;

begin
WriteLn(Test[5]); //Would call __getitem__(5)
end.

From: Markus

program new;
begin
writeln(IntToHex(1234));
end.

Exception in Script: Don't know which overloaded method to call with params (Int32) at line 3, column 9

casting it to integer manually also does not work..


IntToHex(1024, 8) = '00000400'

nielsie95

2012-02-14 13:45:58

From: Markus

program new;
begin
writeln(IntToHex(1234));
end.

casting it to integer manually also does not work..\

edit: terminatescript also doesnt work lol

edit2:
No bounds checking? ;)

As Dgby stated, you need another parameter. TerminateScript is not part of the engine and bounds checking is indeed still lacking.

From: Dgby714
Can you add a way to call a script method from Simba? Like say RuntimeClass.CallProc? I know the runtime is currently just a procedure but It'd be nice.

Also can we get Pause, Resume, Stop, StepInto, StepOver?

Lastly a way to overload operators for types?

Could also go the Python way and just look for something like __set__ and __get__? maybe even allow use to use __getitem__ and __setitem__?

Pause, Resume, Stop, StepInto, StepOver will be part of the debugger. It's on my to-do list. CallProc isn't possible in the way it is now (using variants as parameters). Perhaps I'll add a way to get a method by its name, but you'd still have to call it yourself (using the proper header).

Overloaded operators will probably be possible someday, but it doesn't have high priority at all.. The getitem and setitem should be possible in a similar way using default Delphi/FPC syntax with the "default" keyword.

Dgby714

2012-02-14 14:15:37

From: nielsie95
TerminateScript is not part of the engine

Pause, Resume, Stop, StepInto, StepOver will be part of the debugger. It's on my to-do list.

CallProc isn't possible in the way it is now (using variants as parameters). Perhaps I'll add a way to get a method by its name, but you'd still have to call it yourself (using the proper header).

Overloaded operators will probably be possible someday, but it doesn't have high priority at all.. The getitem and setitem should be possible in a similar way using default Delphi/FPC syntax with the "default" keyword.


It be nice to add a way to try and stop the script properly. Currently hitting the Stop button in Simba just kills the TThread.

Yeah, calling with the correct header would be fine. How hard would this be to implement?

='( I wanted it. And I'm looking into the default thing.

Edit: Ah I see - http://wiki.freepascal.org/Class

Daniel

2012-02-19 00:15:33

Hey Niels, just wondering, but how will forms be implemented in Lape? :S

nielsie95

2012-03-02 08:46:41

From: Dgby714
Yeah, calling with the correct header would be fine. How hard would this be to implement?

Shouldn't be hard to implement, although it might be troublesome to pass the parameters.

From: Daniel
Hey Niels, just wondering, but how will forms be implemented in Lape? :S


Forms will be implemented using imported classes, just like in PS. Or isn't that what you meant?

Also, I really appreciate that you're using Lape for the competition. A little problem might be that this thread is in members, but your thread is also for the ranks below. Another thingy is that Lape support is still experimental, so perhaps you could consider allowing PS entries too. You are right though, it's a great test case.

Daniel

2012-03-02 08:51:57

From: nielsie95

Forms will be implemented using imported classes, just like in PS. Or isn't that what you meant?


I meant creating forms in Lape. i.e., is it possible doing what we are used to and calling TForm.Create to create an instance of a form class?
From: nielsie95

Also, I really appreciate that you're using Lape for the competition. A little problem might be that this thread is in members, but your thread is also for the ranks below. Another thingy is that Lape support is still experimental, so perhaps you could consider allowing PS entries too.

It should all be okay :) Lape is available in current stable builds of Simba, and the syntax isn't completely different to what they're used to in PascalScript. :) If users do start to report errors, I will forward them on to you and state in the thread the interpreter I will be using. But I've never experienced any errors from Lape doing random things, so it should all hopefully be okay :p

masterBB

2012-03-02 09:43:39

I'm aware that bounds checking is missing, but I can't explain this returns 30:
a := [0,2,3,4,5,2,3];
writeln(a[23]);

nielsie95

2012-03-02 09:49:27

From: Daniel
I meant creating forms in Lape. i.e., is it possible doing what we are used to and calling TForm.Create to create an instance of a form class?

Yup, that should work.

From: masterBB
I'm aware that bounds checking is missing, but I can't explain this returns 30:
a := [0,2,3,4,5,2,3];
writeln(a[23]);

Everything outside the bounds is undefined, so the 30 is a random point in your memory (it will not always be 30). Changing it may result in weird behavior, because you don't know what you're changing.

Gu3st...

2012-03-07 17:26:01

From: nielsie95
Everything outside the bounds is undefined, so the 30 is a random point in your memory (it will not always be 30). Changing it may result in weird behavior, because you don't know what you're changing.
So if you're not careful, you might end up changing memory bits that isn't even allocated by Simba?

nielsie95

2012-03-08 02:44:03

That is impossible, but if you're not careful you might end up making unwanted changes to unknown variables. In the worst case you'll crash Simba, not the system. Same story with pointers. That is why they aren't supposed to be in scripting languages, which are meant to give you a boxed environment.

Gu3st...

2012-03-08 02:50:43

From: nielsie95
That is impossible, but if you're not careful you might end up making unwanted changes to unknown variables. In the worst case you'll crash Simba, not the system. Same story with pointers. That is why they aren't supposed to be in scripting languages, which are meant to give you a boxed environment.
Okay good :p

masterBB

2012-03-17 10:32:14

Also posted this somewhere else. But it is a nice benchmark! Note that labels are a tiny bit faster than a for loop. Pascals script is very very slow, especially with labels.

Successfully executed.
Compiled successfully in 15 ms.
468
484
Successfully executed.
Compiled successfully in 16 ms.
19999
10936

program new;

{$Define lape}

procedure Test1;
label
start;
var
i,b:Integer;
begin
i := 0;
start:
inc(i);
inc(b);
if i < 10000000 then
goto start;
end;

procedure Test2;
var
i,b:Integer;
begin
for i := 0 to 10000000 do
inc(b);
end;

var
timer:Integer;

begin
{$IFDEF lape}
timer := GetTickCount;
Test1;
writeln(GetTickCount - timer);

timer := GetTickCount;
Test2;
writeln(GetTickCount - timer);
{$ELSE}
timer := GetSystemTime;
Test1;
writeln(GetSystemTime - timer);

timer := GetSystemTime;
Test2;
writeln(GetSystemTime - timer);
{$ENDIF}
end.

edit:
Larger amounts shows the difference better between labels and loops:
Successfully executed.
Compiled successfully in 15 ms.
4540
5632

nielsie95

2012-03-17 10:42:04

In general, a mere loop isn't a good way to benchmark as it doesn't represent regular usage. But it's a nice observation indeed! :)


Compiled successfully in 16 ms.
452
343
Successfully executed.
Just the other way around for me :p

masterBB

2012-03-17 10:46:52

I guess that's the difference between hardware and maybe drivers. If I use bigger quantities the difference gets larger and larger… how odd.

masterBB

2012-03-27 13:32:52

var
a:Extended;

begin
a := 3 / 150000 * 50000;
writeln(a);
end.

Is 0 on pascalscript but 1 on lape. Seems like lape uses the extended type while calculating. No longer loss of precesion there.

Also it gives an error when variable a is of the type Integer.

var
a:Integer;

begin
a := 3 / 150000 * 50000;
writeln(a);
end.

nielsie95

2012-03-27 13:44:28

The difference is in the division operator. Pascal Script only does floating point division if one of the operands is a float. Lape does floating point division with the / operator and integer division with the div operator. So this is expected behaviour :)

Pascal Script also supports the div operator, but just for fun I guess.

In other news: I've been able to successfully run a script on native Linux x64 using SMART :D

Yago

2012-03-28 18:57:58

From: nielsie95
The difference is in the division operator. Pascal Script only does floating point division if one of the operands is a float. Lape does floating point division with the / operator and integer division with the div operator. So this is expected behaviour :)

Pascal Script also supports the div operator, but just for fun I guess.

In other news: I've been able to successfully run a script on native Linux x64 using SMART :D


Nice, would you be able to give us basic steps as to how to do so?

Edit: NVM got it

BraK

2012-04-05 21:26:36

I stickied the thread in here because I think Lape should always be stickied. :)

nielsie95

2012-05-17 10:23:51

As you might have seen in the latest threads for the release candidates of Simba and SMART, I added support for libffi. This means that wrapper functions are not required any more and regular libraries may be imported (such as SMART without EIOS or Windows libraries). The functionality is comparable with Pascal (Script)'s external keyword. Currently, this functionality is only accessible through the back-end, so you can only load libraries through {$loadlib lib} for now.

Anyway, I've seen a lot of people on the forums who did not know exactly what Lape would/could mean for them. Some were afraid it would mean they had to learn a new language (which is not the case! :)) or had other questions. This thread is here for your questions. Feel free to ask them!

masterBB

2012-05-17 10:27:03

I think the problem with this thread is that it is for srl members+, maybe there should be a thread to inform other users as well?

nielsie95

2012-05-17 10:30:43

It only concerns scripters and Lape is still in an alpha stage, so I want to reach SRL members only for now. :)

BraK

2012-08-15 20:26:33

Sooooo Is there a Release thread for Lape lower than Members goodies yet as it's openly talked about. Might consider moving this on down to Public.

Also…..

Pretty, Pretty Please niels can I get forms included into LAPE. I'm totally motivated to switching my script over to LAPE thanks to your Linux 64bit smart V8.0 script release. I totally blame you for me being so motivated. ;)

nielsie95

2012-08-17 09:08:47

It's not like I add features just by snapping my fingers :p
I've been running into design problems because of some bad decisions earlier in the project, so that makes it a bit harder to add bigger features. I'll still try to fix bugs and add imported classes/forms, but I do not rule out a rewrite after that.

I'm not sure what a thread for non-members would be good for, as they would probably only get hyped up for nothing. They should not have to notice anything from a switch from PS to Lape. I don't want it to turn into something like the script manager which "is almost finished" for over a year now. Lape is well under way, usable even, but not ready for the public. Perhaps I'll move this thread when SRL and Simba are working with Lape out-of-the-box. (I actually had SRL, MSI, SMART running - and SPS/SMART graphics compiling - a few months ago, but the branches were not merged and now they are out of sync again).

You guys can help me being motivated though, by fiddling with Lape, creating scripts and finding bugs! ;)

To quote myself:
From: nielsie95
It only concerns scripters and Lape is still in an alpha stage, so I want to reach SRL members only for now. :)
From: nielsie95
Anyway, I've seen a lot of people on the forums who did not know exactly what Lape would/could mean for them. Some were afraid it would mean they had to learn a new language (which is not the case! :)) or had other questions. This thread is here for your questions. Feel free to ask them!

Wizzup?

2012-08-19 05:01:07

From: nielsie95
It's not like I add features just by snapping my fingers :p
I've been running into design problems because of some bad decisions earlier in the project, so that makes it a bit harder to add bigger features. I'll still try to fix bugs and add imported classes/forms, but I do not rule out a rewrite after that.

I'm not sure what a thread for non-members would be good for, as they would probably only get hyped up for nothing. They should not have to notice anything from a switch from PS to Lape. I don't want it to turn into something like the script manager which "is almost finished" for over a year now. Lape is well under way, usable even, but not ready for the public. Perhaps I'll move this thread when SRL and Simba are working with Lape out-of-the-box. (I actually had SRL, MSI, SMART running - and SPS/SMART graphics compiling - a few months ago, but the branches were not merged and now they are out of sync again).

You guys can help me being motivated though, by fiddling with Lape, creating scripts and finding bugs! ;)

To quote myself:


Maybe lape is where it is now is partially responsible the delay of the script manager. ;)

Flight

2012-08-21 08:37:04

From: nielsie95

You guys can help me being motivated though, by fiddling with Lape, creating scripts and finding bugs! ;)


In that case, I'm not sure if this is normal or a bug but trying to compare two points seems to be giving me an error in Lape:

Exception in Script: Operator "cmp_Equal" not compatible with types at line 281, column 29

Here's where the error is generated:

Result := (GetGardenPos = Point(2,3));

FYI, the function 'GetGardenPos' returns a TPoint. Now why would this be a incorrect statement? Also, apparently one cannot divide extended integers by using "div", one must instead use "/", but that's not such a big deal.


Edit:
Oh yes, I did have a fairly simple question as well. If Lape does not affect color-finding at all, then why would it have an advantage over PascalScript? I imagine the advantages of Lape would be limited to just mathematical procedures as well as loops, yes? Also it brings fourth new tools to be used in scripts, for example Pointers. Beyond this, what's the advantages over PascalScript?

Edit2:
Just to clarify, I see the advantages on the OP, but I'm asking more in relation to advantages in color-finding (and so on…) via Lape. Is there any differences in that area?

masterBB

2012-08-21 08:57:33

As you can see here:

https://github.com/MerlijnWajer/Simba/blob/master/Units/MMLCore/mufasatypes.pas#L416

The operator is changed in simba for TPoints. I don't think lape got this function yet. I think the best workaround at this moment is a function PointComp();

nielsie95

2012-08-21 10:08:23

From: Flight
In that case, I'm not sure if this is normal or a bug but trying to compare two points seems to be giving me an error in Lape:

Here's where the error is generated:

Result := (GetGardenPos = Point(2,3));

FYI, the function 'GetGardenPos' returns a TPoint. Now why would this be a incorrect statement? Also, apparently one cannot divide extended integers by using "div", one must instead use "/", but that's not such a big deal.

Perhaps it's more of a missing feature than a bug, or just a nice extra in Pascal Script (this is not in Pascal Script by default, I added it). But it's probably a good idea to implement it in Lape, too. There are two ways to do this:


program new;
var
a, b: record
s: string;
end;
begin
a.s := 'ye' + 'ap';
b.s := 'yeap';
WriteLn(a = b);
a.s := b.s;
WriteLn(a = b);
end.
The first comparison will result false in Pascal Script, because it compares the entire record at once instead of comparing each of the properties. Perhaps it's better to compare properties in Lape?

As for div, see my previous post on this (in this thread). Div is used for integer division in Pascal.

From: Flight

Edit:
Oh yes, I did have a fairly simple question as well. If Lape does not affect color-finding at all, then why would it have an advantage over PascalScript? I imagine the advantages of Lape would be limited to just mathematical procedures as well as loops, yes? Also it brings fourth new tools to be used in scripts, for example Pointers. Beyond this, what's the advantages over PascalScript?

Edit2:
Just to clarify, I see the advantages on the OP, but I'm asking more in relation to advantages in color-finding (and so on…) via Lape. Is there any differences in that area?

It should be noted that the functions which are not run through the interpreter, can not be sped up by the interpreter. So functions like FindColor, ClickMouse, FindBitmap, basically all the functions you can find in the function list on the left (minus Script and Includes), are already compiled. The interpreter just calls them with the proper variables and waits for the result. The time it takes to call such a function is pretty much negligible, the rest of the time is just the time it takes to search for a colour or bitmap.

Lape can make your life easier with little extras such as overloaded functions or default parameters, but is also faster on the interpreter side. So functions/calculations done in your script (in the function list: everything under Script and Includes) should be faster. It takes less time to add two numbers, iterate an array, check if certain conditions are true, etcetera. It's just more efficient.

To answer your question, "Also it brings fourth new tools to be used in scripts, for example Pointers. Beyond this, what's the advantages over PascalScript?": cross-platform, if that counts. Other than that, I can't think of of any advantages. (Not sure what else it could offer, though).

Flight

2012-08-21 10:22:41

I see, well that does clear up a lot of what I was wondering about. Thank you very much, Nielsie.

NKN

2012-08-21 10:37:18

From: nielsie95
It's just a more efficient.



OffTopic: Made me think of Mario with that 'a' there.

OnTopic: So anything built into Simba won't be sped up, but mathematics and arrays such will be faster?

Chris

2012-08-23 08:01:16

I think that I've found a bug,
Running this with Lape:
program new;

procedure test;
var
i: Integer;
t: array [0..2] of integer;
begin
for t[0] := 1 to 5 do
for t[1] := 1 to 5 do
for t[2] := 1 to 5 do
inc(i);
writeln(i);
end;

begin
test;
end.

Writes 5..
When I make t global instead of local, it does write 125, but it should also work as a local variable is what I thought :D
I might aswell be completely wrong.

masterBB

2012-08-23 09:21:58

Good find, I can confirm this bug. How odd.

lape:
[1, 1, 1]
[1, 1, 2]
[1, 1, 3]
[1, 1, 4]
[1, 1, 5]

It seems to able to loop fine with integers, but something of the integer array makes it skip out of the for loop, or maybe use the last value out of the array.

program new;

procedure test;
var
i: Integer;
t: array [0..2] of integer;
begin
for t[0] := 1 to 8 do //if that number is >= 8 then it will loop forever, 6 and 7 works the same as 5 or any other number.
for t[1] := 1 to 5 do //if that number is >= 7 then it will loop forever, 6 works the same as 5 or any other number.
for t[2] := 1 to 5 do
writeln(t);
end;

begin
test;
end.

Even more interesting result.

nielsie95

2012-08-23 11:40:32

Should definitely work. Nice find! Not sure what's causing it.

Gu3st...

2012-10-14 11:44:43

Why doesn't this throw an error?
var
TPA : TPointArray;
begin
SetLength(TPA, 20);
WriteLn(TPA[30]);
end.

or this:
var
TPA : array [0..20] of TPoint;
begin
WriteLn(TPA[30]);
end.

BraK

2012-10-14 11:47:26

Niels I got asked to make a sub-forum for LA-PE in the SRL development Section would you be okay with this? I asked wizzup already and he's fine with it. Just wanted to ask you first. Also I post some bugs to your code.google repo a few days ago.

Also I got this error the other day.

Exception in Script: Expected variable of type "array of array of AnsiString", got "array [0..3] of array [0..3] of AnsiString" at line 29, column 17 at line 29, column 18

litoris

2012-10-14 11:47:59

From: Zyt3x
Why doesn't this throw an error?
var
TPA : TPointArray;
begin
SetLength(TPA, 20);
WriteLn(TPA[30]);
end.

or this:
var
TPA : array [0..20] of TPoint;
begin
WriteLn(TPA[30]);
end.


What does it do instead? Extend the length of the array and debug zero?
E: Just read about the random point in memory thingy, nvm

Markus

2012-10-16 23:12:12

16 lines of code. Runme!

program new;
var a, b,c : integer;
begin
a := 1;
b := 2;
c := 5;
while ((a > 0) or (b > 0) or (c > 0)) do
begin
a := max(0, a-1);
b := max(0, b-1);
c := max(0, c-1);
writeln('A: '+tostr(a)+' B: '+tostr(b)+' C: '+tostr(c));
end;
writeln('****');
writeln('A: '+tostr(a)+' B: '+tostr(b)+' C: '+tostr(c));
end.

Looks like Lape doesn't understand triple conditionals right :)

nielsie95

2012-10-19 08:27:16

Lape is still in the alpha phase, but I think this section suits the thread better.

Gu3st...

2012-10-19 23:55:21

var
a : function() : Integer = nil;

function testfunc() : integer;
begin
Result := 42;
end;

begin
//WriteLn(a); // Shouldn't this out-put "nil"? Errors in "Invalid jump" atm..
a := @testfunc;
WriteLn(a);
end.

How do I check if the function is not set (line "a := @testfunc;" has not yet been called)?
Also, shouldn't there be a difference from doing WriteLn(a); and doing WriteLn(a());?

nielsie95

2012-10-20 03:15:44

Use {$AutoInvoke Off} if you want to call functions explicitly.


var
a : function() : Integer = nil;

function testfunc() : integer;
begin
Result := 42;
end;

begin
{$AutoInvoke Off}
WriteLn(a);
a := testfunc;
WriteLn(a, ' -> ', a());

a := nil;
{$AutoInvoke On}
WriteLn(@a);
a := @testfunc;
WriteLn(@a, ' -> ', a);
end.

nielsie95

2012-11-04 14:28:29

From: Chris
I think that I've found a bug,
Running this with Lape:
program new;

procedure test;
var
i: Integer;
t: array [0..2] of integer;
begin
for t[0] := 1 to 5 do
for t[1] := 1 to 5 do
for t[2] := 1 to 5 do
inc(i);
writeln(i);
end;

begin
test;
end.

Writes 5..
When I make t global instead of local, it does write 125, but it should also work as a local variable is what I thought :D
I might aswell be completely wrong.


From: Markus
16 lines of code. Runme!

program new;
var a, b,c : integer;
begin
a := 1;
b := 2;
c := 5;
while ((a > 0) or (b > 0) or (c > 0)) do
begin
a := max(0, a-1);
b := max(0, b-1);
c := max(0, c-1);
writeln('A: '+tostr(a)+' B: '+tostr(b)+' C: '+tostr(c));
end;
writeln('****');
writeln('A: '+tostr(a)+' B: '+tostr(b)+' C: '+tostr(c));
end.

Looks like Lape doesn't understand triple conditionals right :)


I think I fixed the above bugs. Hopefully I did not introduce new ones :)
Thanks for testing!

Dgby714

2012-11-04 15:08:29

From: nielsie95
I think I fixed the above bugs. Hopefully I did not introduce new ones :)
Thanks for testing!


Thanks for making Lape =)

Will get Wizzup to update Simba's submodule soon =P

Markus

2012-11-04 15:09:28

From: Dgby714
Thanks for making Lape =)

Will get Wizzup to update Simba's submodule soon =P


Yea please do so. Else I'll have to threaten to poison his chocolate milk once again.

NKN

2012-11-04 16:13:03

From: Markus
Yea please do so. Else I'll have to threaten to poison his chocolate milk once again.

Not the chocolate milk…

Albi

2012-11-11 13:03:35

Would there be any possibility of perhaps writing a Ruby interpreter in the future?

Le Jingle

2012-11-29 22:51:38

Curious to the skeleton for Abilities (which I think would take place under SRL6/SRL/lib/interfaces/gametab/abilities), would it be recommended to look over other includes like bank.simba, when simply acquiring function placeholders?

And you have to forward in functions from other includes still, no? -> Like if I wanted to use If GameTab(..) then?

Is there also any chance to have ++/– implemented?

NCDS

2012-11-29 22:57:41

From: Le Jingle
Curious to the skeleton for Abilities (which I think would take place under SRL6/SRL/lib/interfaces/gametab/abilities), would it be recommended to look over other includes like bank.simba, when simply acquiring function placeholders?

And you have to forward in functions from other includes still, no? -> Like if I wanted to use If GameTab(..) then?

Is there also any chance to have ++/– implemented?


You may find this interesting.

Le Jingle

2012-11-29 23:41:20

From: NCDS
You may find this interesting.


Ahh! I didn't know that you could use constructs (I think I got that right?) in lape; although I did notice the inherited() (I think inherited is somewhat similar to overloading?) and overload()'s.

Guess I'll start following a couple SRL6's just to be up-to-date to my liking :)

Thanks NCDS!

Cheers,
Lj

Dgby714

2012-11-30 02:25:27

From: Le Jingle
Ahh! I didn't know that you could use constructs (I think I got that right?) in lape; although I did notice the inherited() (I think inherited is somewhat similar to overloading?) and overload()'s.

Guess I'll start following a couple SRL6's just to be up-to-date to my liking :)

Thanks NCDS!

Cheers,
Lj


When you override a function, you can call it's parent with inherited();

masterBB

2012-12-05 09:13:41

http://code.google.com/p/la-pe/issues/detail?id=20

footballjds

2012-12-05 10:48:49

Literally checked out this thread for the first time. EXTREMELY excited about LAPE!!!

Form support? :p

masterBB

2012-12-05 10:58:55

From: footballjds
Literally checked out this thread for the first time. EXTREMELY excited about LAPE!!!

Form support? :p


yes and no.

It is possible to implement, but no one did yet.

nielsie95

2012-12-11 12:04:06

From: masterBB
http://code.google.com/p/la-pe/issues/detail?id=20


If you post on Google code, I respond on Google code.

BraK

2012-12-11 12:18:49

Psssst Forms Pssssst ;)

Dgby714

2012-12-11 13:34:45

From: BraK
Psssst Forms Pssssst ;)


Meh, not currently worth it unless niels adds some easier way to do it….

OR, I can make a thread-less version of Simba for us to use…. would make things easy.

OR, I can make a UI for TScriptExample and finish adding MML to it and it would even have some new features I plan to integrate into Simba.

Olly

2012-12-11 16:54:06

From: Dgby714
Meh, not currently worth it unless niels adds some easier way to do it….

OR, I can make a thread-less version of Simba for us to use…. would make things easy.

OR, I can make a UI for TScriptExample and finish adding MML to it and it would even have some new features I plan to integrate into Simba.


do it!

nielsie95

2012-12-24 13:44:14


{$assertions on}

type
t1 = record
a: Integer;
end;

t2 = record(t1)
b: Integer;
end;

function t1.getA: Integer;
begin
Result := a + 1;
end;

function t2.getA: Integer; override;
begin
Result := inherited() - 1;
end;

var
a: t1 = [1];
b: t2 = [2, 3];
begin
Assert(a.getA() = 2);
Assert(b.getA() = 2);
end;

No forms, but might be interesting nonetheless. This is a test case from the latest Lape commit; it shows basic record inheritance (record t2 gets the same attributes/methods as t1, plus additions).

masterBB

2012-12-24 13:53:58

Wow! Great job. I can imagine this brings us a few steps closer to scripting OOP. Though I see no use in it for runescape bots.

Gu3st...

2013-01-01 23:37:29

var
s : array of String;
I : Integer;
begin
setLength(s, 2);
s[1] := 'FFFFFF';
setLength(s, 1);
s[1] := 'FFFFFF'; // No access violation here.
// Doing setLength(s, 0) instead raises the access violation when calling s[1].

for I := 0 to 10 do
begin
writeLn(I);
s[I] := 'FFFFFF'; // Access violation here, but I is looped 6 times before the violation is raised when length of s = 1.
end;
end.
Weird behaviour..

Also, I'd like it if you could make the toStr use the pointer to the function instead of calling the function when using it like this:
type
testType = record
b : boolean;
f : extended;
s : function : boolean;
end;

var
a : testType;

function test : boolean;
begin
end;

begin
a.s := @test;
writeLn(toStr(a));
writeLn(toStr(@a.s));
end.

Brandon

2013-01-01 23:49:31

It isn't calling the function:


function test : boolean;
begin
writeln('Called');
Result := true;
end;

If it did, the above would print "Called". Your code prints possible return values which are followed by the function's name and address after the scope operator:


Compiled successfully in 312 ms.
function():(False=0, True=1) ("test"::0x4050)
Successfully executed.

The other set length stuff is just weird though..

Gu3st...

2013-01-01 23:55:34

You're wrong, it does call the function. This is also my point: I'd like it if toStr(a) used the pointer to the function instead, so that for those times you don't assign a function to the variable it wont error out.

Try messing around un-commenting and re-commenting a.s := @test; here:
type
testType = record
b : boolean;
f : extended;
s : function : boolean;
end;

var
a : testType;

function test : boolean;
begin
WriteLn('hoi');
end;

begin
//a.s := @test;
writeLn(toStr(@a.s));
writeLn(toStr(a));
end.

When commented:
Compiled successfully in 110 ms.
function():(False=0, True=1) (nil)
Exception in Script: Runtime error: "Access violation"

When not commented:
Compiled successfully in 109 ms.
function():(False=0, True=1) ("test"::0x4118)
hoi
{B = False, F = 0, S = False}
Successfully executed.

Also note the "hoi" which means it did indeed call the function.

Brandon

2013-01-02 00:09:32

From: Zyt3x
You're wrong, it does call the function.

Also note the "hoi" which means it did indeed call the function.



I'm afraid, you're wrong this time. The reason you see the "hoi" is because you put:

writeln(a);

Which goes through the entire class and gets the values point to. Inorder to get the boolean value which is what the function returns, writeln calls the function. ToStr does not. Writeln will error out because you're calling a pointer to a function that is null.

if you did:

writeln(tostr(@a.s));

it does nothing but print the address of the function even if not assigned (in which case it prints nil)..


If I'm missing something here, I apologize.

Gu3st...

2013-01-02 00:11:19

From: Brandon
I'm afraid, you're wrong this time. The reason you see the "hoi" is because you put:

writeln(a);

Which goes through the entire class and gets the values point to. Inorder to get the boolean value which is what the function returns, writeln calls the function.

if you did:

writeln(tostr(@a.s));

it does nothing but print the address of the function..


If I'm missing something here, I apologize.
So basically you're saying "Calling toStr(a) will call the function s, that's why you see 'hoi'."

And then I'm saying "Yes, that's what I want changed".

Why are we arguing?

Brandon

2013-01-02 00:13:29

From: Zyt3x
So basically you're saying "Calling toStr(a) will call the function s, that's why you see 'hoi'."

And then I'm saying "Yes, that's what I want changed".

Why are we arguing?


Ohhh I see! I thought you wanted to do ToStr(@a.s).. which I see as normal. Ahahaha oopsie.

In that case, why not store a pointer to the function in the record/class rather than the function itself?

Edit: NVM.. stupid idea.

EDIT:


type
testType = record
b : boolean;
f : extended;
s : Pointer;
end;

var
a : testType;

function test : boolean;
begin
WriteLn('hoi');
end;


var
Foo : function: Boolean;

begin
a.s := @test;

Foo := a.s;

Foo();
end.

Something like this can work.. Now your S can be anything you wish. Still.. The tostr should be fixed I guess.. Though, this is a viable solution for now?

Gu3st...

2013-01-02 01:20:00

Yeah, but a pointer is a pointer… :S
And it basically was a pointer as "s : function() : Boolean;" too, just a "safer" version of a pointer..

I see more problems by having it like it is now anyways, and should be redone. Not setting a function to it (leaving it nil) shouldn't throw errors imo :p

Another way around the problem is to make a separate "toString" function in the type (which I used, while waiting for a fix).
type a = record s : function() : Boolean; end;

function a.toString(): Boolean;
begin
Result := '{S = ' + toStr(@s); + '}'
end;

nielsie95

2013-01-02 05:56:11

Thank you, will be fixed! :)

By the way, you didn't have to create another toString to work around it, you could've overridden the old one:

type a = record s : function() : Boolean; end;

function toString(const rec: a): string; override;
begin
Result := 'a: {S = ' + toStr(@rec.s); + '}';
end;

Gu3st...

2013-01-03 06:18:23

Another thing, could you make a switch statement in addition to the case statement, where the difference is the switch statement works like the switch statement in i.e php where it will not exit the statement unless told to exit it.

Example:
begin
switch 0 of
0: writeLn('0'); // put break; here to exit or w/e
1: writeLn('0 or 1');
end;
end.

E: or make it so that it will iterate to the next valid one instead of exiting. Maybe turn it on with a {case_continueIteration on} option or something, but leave it off by default?

Example:
begin
case 0 of
0: writeLn('0');
1: writeLn('1');
0, 1: writeLn('0 or 1');
end;
end.

nielsie95

2013-01-03 20:14:01

I've implemented it like this:

{$ContinueCase ON}
begin
case 2 of
1: begin WriteLn('1'); Continue; end;
2: begin WriteLn('2'); Continue; end;
3: begin WriteLn('3'); Continue; end;
4: begin WriteLn('4'); end;
5: begin WriteLn('5'); Continue; end;
else WriteLn('else');
end;
WriteLn('out');
end;

{ Output:
2
3
4
out
}

So by using {$ContinueCase ON}, using continue inside a case statement will make it fall through to the next item. You can still use continue(2) to break out of a loop if necessary.

I've also implemented a few functions today, namely Copy(), Delete() and Insert() for strings and arrays.
Copy will copy (part of) any array/string and returns a new array/string.
Delete will delete part of any dynamic array/string.
Insert will insert a new item or a subarray into a dynamic array/string at a given position.

const
arr = [5..8];
var
a: array of Int32 = [1..5];
begin
Insert(0, a); //Prepend 0
Insert(6, a, Length(a)); //Append 6
Insert([-2, -1], a); //Prepend -2, -1
WriteLn(a);

Insert(arr, a, 3, 4); //Replace 1..4 with 5..8
WriteLn(a);

Delete(a, 0, 2); //Delete first two
Delete(a, 4); //Delete everything starting at idx 4
WriteLn(a);

WriteLn(Copy(a)); //Copy a
WriteLn(Copy(a, 2)); //Copy a, starting at idx 2
WriteLn(Copy(a, 1, 2)); //Copy two elements starting at idx 1
end;

Gu3st...

2013-01-03 22:55:21

Thanks! That case loop option is really helpful :)

Also, about those copy/delete/insert functions.. Why didn't you add those yesterday so that I'd spare myself for some hours of function creating today :(
https://github.com/SRL/SRL-6/blob/master/lib/utilities/types.simba

Coh3n

2013-01-03 23:43:05

From: Zyt3x
Thanks! That case loop option is really helpful :)

Also, about those copy/delete/insert functions.. Why didn't you add those yesterday so that I'd spare myself for some hours of function creating today :(
https://github.com/SRL/SRL-6/blob/master/lib/utilities/types.simba
I still like the type functions better. I wouldn't mind keeping them in SRL-6.

@nielsie, do you have any documentation for lape? It would probably make it easier since a lot of functions are overloaded.

Gu3st...

2013-01-03 23:53:36

From: Coh3n
I still like the type functions better. I wouldn't mind keeping them in SRL-6.
My point was that I have to re-do a lot of the functions now :p

nielsie95

2013-01-04 05:27:11

Looking pretty good :) Perhaps some of these type functions should be in Lape too?

There's no documentation other than the tutorial in progress from Wizzup? But feel free to ask how a function can be used.
Also, anyone want to contribute to Wizzup's tutorial? I've seen a few good explanations of pointers! :)

Gu3st...

2013-01-04 05:35:17

Adding these to lape itself would be awesome :D I have no idea how to do it though, so it'll have to wait

Coh3n

2013-01-10 21:42:34

I have a suggestion nielsie. Something like type functions, but for functions.

program new;

function gameTab(tab: integer).toStr(): string;
begin
case i of
TAB_LOGOUT: 'TAB_LOGOUT';
TAB_INVENTORY: 'TAB_INVENTORY';
end;
end;

begin
writeln(gameTab(TAB_LOGOUT).toStr());
end.
Would be very useful for debugging constants. If there's another way of doing so, please let me know.

E: I'm not sure if a constant.toStr() function would be possible, but that would also work.

Daniel

2013-01-10 23:04:46

From: Coh3n
I have a suggestion nielsie. Something like type functions, but for functions.

program new;

function gameTab(tab: integer).toStr(): string;
begin
case i of
TAB_LOGOUT: 'TAB_LOGOUT';
TAB_INVENTORY: 'TAB_INVENTORY';
end;
end;

begin
writeln(gameTab(TAB_LOGOUT).toStr());
end.
Would be very useful for debugging constants. If there's another way of doing so, please let me know.

E: I'm not sure if a constant.toStr() function would be possible, but that would also work.


You could instead do:


program new;

function gameTab(tab: Integer): Boolean;
begin
case i of
TAB_LOGOUT: Result := True;
...
end;

function gameTab(tab: integer): string; override;
begin
case i of
TAB_LOGOUT: 'TAB_LOGOUT';
TAB_INVENTORY: 'TAB_INVENTORY';
end;
end;

begin
writeln(gameTab(TAB_LOGOUT).toStr());
end.

Coh3n

2013-01-11 15:50:58

I wouldn't want to override gameTab, though, as gameTab would work like it always has. I suppose I could just add a gameTabToStr function that would do the same, but having the ability to just do constant.toStr would be a lot nicer.

Dgby714

2013-01-11 16:14:30

From: Coh3n
I wouldn't want to override gameTab, though, as gameTab would work like it always has. I suppose I could just add a gameTabToStr function that would do the same, but having the ability to just do constant.toStr would be a lot nicer.


Make TGameTab as a enumeration?

program new;

type
TGameTab = (TAB_LOGOUT = 37);

function ToString(x: TGameTab): string; override;
begin
case x of
TAB_LOGOUT: Result := 'Logout Tab';
end;
end;

begin
WriteLn(TAB_LOGOUT, ' = ', Ord(TAB_LOGOUT), ';'); // Logout Tab = 37;
end.

Dgby714

2013-01-11 16:40:11

Hmmm, Suggestion, Can we get something like class methods in classes?

Say you make a record method, but it doesn't need an initialized variable to be used.

So I could say TGameTab.Current() instead of TAB_SOMETAB.Current()…


program new;
{$C+}{$B+}{$M+}{$X+}{$F-}{$S-}

type
TGameTab = (
GameTab, //Use this for shared methods, looks nice
tab_Unknown,
tab_Combat = 21,
tab_Stats,
tab_Quest,
tab_Diary,
tab_Inv,
tab_Equip,
tab_Prayer,
tab_Magic,
tab_Objectives,
tab_Friends,
tab_Ignore,
tab_Clan,
tab_Options,
tab_Emotes,
tab_Music,
tab_Notes,
tab_LogOut
);

function ToString(x: TGameTab): string; override;
begin
case x of
GameTab, tab_Unknown: Result := 'Unknown Tab';
tab_Combat: Result := 'Combat Tab';
tab_Stats: Result := 'Stats Tab';
tab_Quest: Result := 'Quest Tab';
tab_Diary: Result := 'Diary Tab';
tab_Inv: Result := 'Inventory Tab';
tab_Equip: Result := 'Equipment Tab';
tab_Prayer: Result := 'Prayer Tab';
tab_Magic: Result := 'Magic Tab';
tab_Objectives: Result := 'Objectives Tab';
tab_Friends: Result := 'Friends Tab';
tab_Ignore: Result := 'Ignore Tab';
tab_Clan: Result := 'Clan Tab';
tab_Options: Result := 'Options Tab';
tab_Emotes: Result := 'Emotes Tab';
tab_Music: Result := 'Music Tab';
tab_Notes: Result := 'Notes Tab';
tab_LogOut: Result := 'Logout Tab';
end;
end;

function TGameTab.FromStr(x: string): TGameTab; //shared;
begin
x := Replace(Lowercase(x), ' ', '', [rfReplaceAll]);
if (Copy(x, Length(x) - 2, 3) = 'tab') then
Delete(x, Length(x) - 2, 3);

case x of
'combat': Result := tab_Combat;
'stats': Result := tab_Stats;
'quest': Result := tab_Quest;
'diary': Result := tab_Diary;
'inventory', 'inv': Result := tab_Inv;
'equip': Result := tab_Equip;
'prayer': Result := tab_Prayer;
'magic': Result := tab_Magic;
'objectives', 'obj': Result := tab_Objectives;
'friends': Result := tab_Friends;
'ignore': Result := tab_Ignore;
'clan': Result := tab_Clan;
'options': Result := tab_Options;
'emotes': Result := tab_Emotes;
'music': Result := tab_Music;
'notes': Result := tab_Notes;
'logout': Result := tab_LogOut;
else
Result := tab_Unknown;
end;
end;

function TGameTab.ToInt(): Int32;
begin
Result := Ord(Self);
end;

function TGameTab.FromInt(x: Int32): TGameTab; //shared;
begin
//Using this, tho you could easily use a InRange...
//FIXME: GameTab -> TGameTab, after update.
Result := GameTab.FromStr(ToString(TGameTab(x)));
end;

function TGameTab.Current(): TGameTab; //shared;
var
Temp: UInt32;
begin
for Result := tab_Combat to tab_Notes do
begin
Temp := Ord(Result) - 21;
if (GetColor(535 + Temp mod 8 * 30, 169 + Temp div 8 * 298) = 3775717) then
Exit;
end;

Result := tab_Unknown;
end;
//tab_Inv.Current goes here, TGameTab.Current goes to previous
//Will be .Current() later!
function TGameTab.isCurrent(): boolean; //overload; (Should work, as this one is not shared.)
begin
Result := (GameTab.Current() = Self);
end;

function TGameTab.Exists(): boolean;
var
tempCTS: UInt32;
begin
Result := False;
if (Self = GameTab) or (Self = tab_Unknown) or (not LoggedIn()) then
Exit;

tempCTS := GetToleranceSpeed();

try
if (Self = tab_LogOut) then
Exit(getColor(746, 0) = 0);

if (Self = tab_Inv) and (BankScreen()) then
Exit(True);

with (GridBox(Ord(Self) - 20, 8, 2, 13, 18, 30, 300, Point(536, 186))) do
Result := (CountColorTolerance(5005422, x1, y1, x2, y2, 55) < 250);
finally
SetColorToleranceSpeed(tempCTS);
end;
end;

function TGameTab.Select(FKey: boolean = False): boolean;
var
Temp, Tries, T: Int32;
Target: TPoint;
begin
if (Self.isCurrent()) then
Exit(True);

if (not Self.Exists()) then
Exit(False);

if (FKey) then
begin
case (Self) of
tab_Inv: Temp := 1;
tab_Equip: Temp := 2;
tab_Prayer: Temp := 3;
tab_Magic: Temp := 4;
tab_Combat: Temp := 5;
else
Exit(Self.Select(False));
end;

T := GetSystemTime() + 618;
repeat
TypeByte(111 + F);
Wait(150 + Random(100));
Result := Self.isCurrent();
until(Result or (GetSystemTime() > T));

if (not Result) then
Exit(Self.Select(False));
end else
begin
Temp := Ord(Self) - 21;
Target := Point(Temp mod 8 * 30 + RandomRange(527, 545), Temp div 8 * 298 + RandomRange(177, 197));
if (Self = tab_LogOut) then
Target := Point(RandomRange(747, 760), RandomRange(3, 18));

Tries := 0;
while ((Tries < 3) and (not Result)) do
begin
Mouse(Target.X, Target.Y, 0, 0, mouse_left);

T := GetSystemTime;
while (not Result) and (GetSystemTime - T < 2000) do
begin
Result := Self.isCurrent();
Wait(100 + Random(100));
end;

Inc(Tries);
end;
end;
end;

procedure GameTab_Test();
begin
Assert(GameTab.FromInt(1) = tab_Unknown, 'FromInt(1) = tab_Unknown');
Assert(GameTab.FromInt(37) = tab_LogOut, 'FromInt(37) = tab_LogOut');
Assert(GameTab.FromStr('logout') = tab_LogOut, 'FromStr(''logout'') = tab_LogOut');
end;

begin
GameTab_Test();
end.

I'd like the GameTab.FromType methods to be able to be used like TGameTab.FromType(bleh)



ALSO, if else shorthand!

MyStr := 'Hello!' if (Ariving) else 'Goodbye!';

Coh3n

2013-01-11 22:46:02

I honestly don't think what you did is necessary for gametabs. We wouldn't want people having to use a type to reference a gametab when a simple integer constant would do just fine. Maybe I don't see the advantages of what you did?

I was just looking for an easy way to debug constants. I can always just add a gameTabToStr to gametab.simba, but if there was a way to have a toStr method for all constants, that would be much better.

Daniel

2013-01-11 23:50:08

From: Coh3n
I wouldn't want to override gameTab, though, as gameTab would work like it always has. I suppose I could just add a gameTabToStr function that would do the same, but having the ability to just do constant.toStr would be a lot nicer.


Trying to do it your way, and using the overload directive, is pretty much exactly the same.

nielsie95

2013-01-12 08:40:34

Can't really imagine how a constant to string would look like. Just create a specific type for it and override ToString.

@Dgby: Was planning on adding that. Shorthand if's are not high on my list.

Coh3n

2013-01-12 12:56:04

Yeah but wouldn't overriding toString mess up the function for when it's used in other situations?

masterBB

2013-01-12 12:58:13

From: Coh3n
Yeah but wouldn't overriding toString mess up the function for when it's used in other situations?


I think, not sure. That ToString is only used in comparison by lape and when you use it.

Coh3n

2013-01-12 13:10:08

Yes, but say I just wanted to debug 37 and not TAB_LOGOUT. ToString(37) would still print 'TAB_LOGOUT' (assuming TAB_LOGOUT = 37) since the original ToString method was overridden.

It may just be easier to have a gameTabToStr function, or even a global SRL constToStr that could handle all SRL constants.

Dgby714

2013-01-13 01:14:38

From: Zyt3x
var
s : array of String;
I : Integer;
begin
setLength(s, 2);
s[1] := 'FFFFFF';
setLength(s, 1);
s[1] := 'FFFFFF'; // No access violation here.
// Doing setLength(s, 0) instead raises the access violation when calling s[1].

for I := 0 to 10 do
begin
writeLn(I);
s[I] := 'FFFFFF'; // Access violation here, but I is looped 6 times before the violation is raised when length of s = 1.
end;
end.
Weird behaviour..

There is no range checking in Lape, you're looping until you hit memory you have no write access to.


From: Zyt3x

Also, I'd like it if you could make the toStr use the pointer to the function instead of calling the function when using it like this:
type
testType = record
b : boolean;
f : extended;
s : function : boolean;
end;

var
a : testType;

function test : boolean;
begin
end;

begin
a.s := @test;
writeLn(toStr(a));
writeLn(toStr(@a.s));
end.

Try {$F-}.

From: Daniel
You could instead do:


program new;

function gameTab(tab: Integer): Boolean;
begin
case i of
TAB_LOGOUT: Result := True;
...
end;

function gameTab(tab: integer): string; override;
begin
case i of
TAB_LOGOUT: 'TAB_LOGOUT';
TAB_INVENTORY: 'TAB_INVENTORY';
end;
end;

begin
writeln(gameTab(TAB_LOGOUT).toStr());
end.

That would be annoying to get to the first one…

From: Daniel
Trying to do it your way, and using the overload directive, is pretty much exactly the same.

Overloading won't work as they have the same parameters.

From: Coh3n
Yes, but say I just wanted to debug 37 and not TAB_LOGOUT. ToString(37) would still print 'TAB_LOGOUT' (assuming TAB_LOGOUT = 37) since the original ToString method was overridden.

It may just be easier to have a gameTabToStr function, or even a global SRL constToStr that could handle all SRL constants.


He was saying make a new type to hold the gametabs, (an enum, like mine)

Then 37 != tab_LogOut, even if tab_LogOut is actually 37

From: Coh3n
I honestly don't think what you did is necessary for gametabs. We wouldn't want people having to use a type to reference a gametab when a simple integer constant would do just fine. Maybe I don't see the advantages of what you did?

I was just looking for an easy way to debug constants. I can always just add a gameTabToStr to gametab.simba, but if there was a way to have a toStr method for all constants, that would be much better.


You know they still are basicly integers right? Just an enumeration with methods.

You can even pass those into the current functions and they would still work.

Just allows you to use some shorthand like

tab_Inv.Select()

Gu3st...

2013-01-14 08:43:52

I don't see the bad side of using enums.. Coh3n, what exactly are you worried about?

Coh3n

2013-01-14 14:06:47

From: Zyt3x
I don't see the bad side of using enums.. Coh3n, what exactly are you worried about?
I'm not sure. I don't think I understood it correctly, but now that I look at it again it makes sense. @Dgby714, you say you can see pass them as integer parameters to functions?

Dgby714

2013-01-14 20:48:28

From: Coh3n
I'm not sure. I don't think I understood it correctly, but now that I look at it again it makes sense. @Dgby714, you say you can see pass them as integer parameters to functions?


Yes, they still correspond to integers, they *might* auto upgrade to integers fine, tho if they don't you can use tab_Bleh.ToInt() or Ord(tab_Bleh).

Tho the old functions should just be upgraded to use TGameTab anyways…. Would automatically take care of rangchecking.

Coh3n

2013-01-14 20:51:42

From: Dgby714
Yes, they still correspond to integers, they *might* auto upgrade to integers fine, tho if they don't you can use tab_Bleh.ToInt() or Ord(tab_Bleh).
Ah okay, thanks. :)

Dgby714

2013-01-19 14:15:53

From: Coh3n
Ah okay, thanks. :)


Want me to go thru SRL-6, and see if I notice any other areas that can benefit from Lapes new features?

Coh3n

2013-01-19 15:58:06

Be my guest. :) There's not too much to go through yet.

Gu3st...

2013-02-14 12:59:31

Inc(0); doesn't work, but this does:

function Integer.next(): Integer;
begin
result := Self;
inc(Self);
end;

begin
writeLn(0.next()); // writes 0
writeLn(0, 0 = 1); // writes 1False
writeLn(0, 0.next() = 1); //writes 1True
writeLn(0); // writes 2
end.
Curious behaviour

Sawyer

2013-02-16 18:18:43

Would lape run like simba? I'm not familiar with it, but I'd like to start learning now so it will be easier later.

i luffs yeww

2013-02-16 19:50:56

From: Sawyer
Would lape run like simba? I'm not familiar with it, but I'd like to start learning now so it will be easier later.


Lape is an interpreter for Simba scripts. The syntax is nearly identical to PascalScript's syntax, so there's not much more to learn. It's basically just adding some features, speeding some stuff up, and adding cross-platform compatibility.

You can already use Lape, by the way. If you want to use it, go to Script > Interpreter, and select Lape. SRL5 won't work with Lape, so there's not much to do with it.

Sawyer

2013-02-16 21:14:27

Aaaaah. I see. Thank you.

CHEATGOD

2013-02-17 13:55:02

So what does the above snippet do then? Looks illogical?

i luffs yeww

2013-02-17 14:51:18

From: CHEATGOD
So what does the above snippet do then? Looks illogical?


What snippet?

i luffs yeww

2013-02-26 02:57:12

Sorry to multi-post.

@niels, I'm confused right now. There's a very good chance that it's my own extremely poor coding, but the error I'm getting (trying to implement Dijkstra's algorithm) doesn't make sense to me.

I'm getting an Invalid Jump error with the following code at line 46 (`g.AddVertex('C', [['A', 8], ['F', 6], ['G', 4]]);`):


type TDictionary = array of TVariantArray;

type TGraph = record
Vertices: array of TDictionary;
AddVertex: procedure(name: string; edges: TDictionary);
_index: Integer;
_names: TStringArray;
end;

procedure TGraph.AddVertex(name: string; edges: TDictionary);
var
i: Integer = 0;
begin
try
if Length(self._names) = 0 then
begin
Inc(self._index);
self._names[self._index] := name;
end;
if (not (self._names[self._index] = name)) then
for i to High(self._names) do
if (name = self._names[i]) then
self._index := i;
except
Writeln('wat');
finally
self._names[Length(self._names)] := name;
end;
SetLength(self.Vertices, Length(self.Vertices) + 1);
self.Vertices[self._index] := edges;
end;

var
g: TGraph;
d: TDictionary;

begin
SetLength(g.Vertices, Length(g.Vertices) + 1);
g.Vertices[0] := [['B', 0], ['C', 1]];
SetLength(g.Vertices, Length(g.Vertices) + 1);
g.Vertices[1] := [['A', 7], ['F', 2]];
Writeln(g.Vertices);

d := [['B', 0], ['C', 1]];
try
g.AddVertex('C', [['A', 8], ['F', 6], ['G', 4]]);
except
Writeln('error');
end;
end.

Again, it's probably just me being bad (both times I tried working on this I have had a few drinks), but I thought maybe it was a bug.

Thanks.

nielsie95

2013-02-26 05:38:42


type TDictionary = array of record Name: string; Weight: Integer; end;

type TGraph = record
Vertices: array of TDictionary;
_index: Integer;
_names: array of string;
end;

procedure TGraph.AddVertex(name: string; edges: TDictionary);
var
i: Integer = 0;
begin
self._index := -1;
for i to High(self._names) do
if (name = self._names[i]) then
self._index := i;

if (self._index < 0) or (self._index >= Length(self._names)) then
begin
self._index := Length(self._names);
SetLength(self._names, self._index + 1);
self._names[self._index] := name;
end;
Insert(edges, self.Vertices[self._index], Length(edges));
end;

var
g: TGraph;
d: TDictionary;
begin
SetLength(g.Vertices, Length(g.Vertices) + 1);
g.Vertices[0] := [['B', 0], ['C', 1]];
SetLength(g.Vertices, Length(g.Vertices) + 1);
g.Vertices[1] := [['A', 7], ['F', 2]];
Writeln(g.Vertices);

d := [['B', 0], ['C', 1]];
try
g.AddVertex('C', [['A', 8], ['F', 6], ['G', 4]]);
except
Writeln('error');
end;

WriteLn(g);
end.

You'll need one of the latest version of Lape to use Insert. Your main problem was adding AddVertex to the record as a property. You do not need to do this for type functions. Also, you need to use SetLength on arrays.
Not wrong, but TVariantArray is not a good idea for something like this. Especially if you could just use records ;)

Gu3st...

2013-02-26 11:24:06

From: Zyt3x
Inc(0); doesn't work, but this does:

function Integer.next(): Integer;
begin
result := Self;
inc(Self);
end;

begin
writeLn(0.next()); // writes 0
writeLn(0, 0 = 1); // writes 1False
writeLn(0, 0.next() = 1); //writes 1True
writeLn(0); // writes 2
end.
Curious behaviour

@nielsie95; could you make it possible to make functions only work with type variables? i.e a function to check if "self" is a type variable (and not an integer or string) or whatever

Coh3n

2013-03-02 13:37:17

From: Zyt3x
@nielsie95; could you make it possible to make functions only work with variables? i.e a function to check if "self" is a variable or whatever
I would like to see type functions only work with self.variable. By that I mean if you're calling type's attribute/function inside another type function, they should only work with the self. prefix. This would allow, for example, TExample.findColor to call Simba's findColor and not think it's calling TExample.findColor. I also think it would get rid of some confusion.

Also, would it be possible to add a WaitFunction function to Lape. One that will work with any function, no matter the number of parameters? Would be very useful for a lot of areas in SRL.

Olly

2013-03-13 00:24:39

@nielsie95

Comparing TPoints would be small but nice, something this throws this.

 if result <> point(-1, -1) then
debug('woot');


Exception in Script: Operator "cmp_NotEqual" not compatible with types at line 93, column 14

Gu3st...

2013-04-01 01:00:41

Getting some really weird bugs here…
var
S : String;
I := 3;

begin
S := toStr(I);
writeLn(S + '-', toStr(I));
end.
This returns -3 instead of 3-3, as it should.

E: TEMP-SOLUTION: Using intToStr() instead works just fine.

tealc

2013-04-01 01:29:35

I was messing around with pointers. I noticed adding and subtracting from pointers does the same thing, but dec(^Integer) and inc(^Integer) don't do the same thing. Is it supposed to be like that.




program new;

var
c,d: Integer;
b,e: ^Integer;

begin

c := 69;
b:=@c;
e:=@c;

d:=random(1000);
e:=e+8*d;
b:=b-8*d;

if(e=b) then writeln('true'); //its always true


end.

When I do something similar with strings I get a "Exeption in script: runtime error: "access violation"" that causes simba to stop responding and I have to stop the program.

Gu3st...

2013-04-01 04:02:45

I found another bug.
Assigning one array of whatever (X : array of a) to another array of the same whatever (Y : array of a), causes the second array (Y) to act as a pointer to the first array (X):
type
a = record
b, c : String;
end;
aArr = array of a;

var
X, Y: aArr;

begin
setLength(X, 1);
setLength(Y, 1);
X[0].b := 'Hoi';
X[0].c := 'Dar';
Y := X; // Creates a new copy of X.
X[0].c := 'Bro'; // Change variables c in X only.
writeLn(X, Y); // Output: [{B = Hoi, C = Bro}][{B = Hoi, C = Bro}]
// Result: Both X and Y are changed, even though we only wanted to change X.
end.

E: TEMP-SOLUTION: Assigning and changing variables one by one works. Y[0].b := X[0].b; Y[0].c := X[0].b; Output: [{B = Hoi, C = Bro}][{B = Hoi, C = Dar}]
E2: The TEMP-SOLUTION I posted earlier does not work with more complicated types, though… Tested it on my vCard parser and it does not seem to do the trick.

Gu3st...

2013-04-02 16:23:41

From: Coh3n
I would like to see type functions only work with self.variable. By that I mean if you're calling type's attribute/function inside another type function, they should only work with the self. prefix. This would allow, for example, TExample.findColor to call Simba's findColor and not think it's calling TExample.findColor. I also think it would get rid of some confusion.

I'm bumping this post to increase it's importance.

Daniel

2013-04-04 09:30:12

From: Zyt3x
I found another bug.
Assigning one array of whatever (X : array of a) to another array of the same whatever (Y : array of a), causes the second array (Y) to act as a pointer to the first array (X)


That is because array's are structured types.

Gu3st...

2013-04-04 16:28:30

From: Daniel
That is because array's are structured types.
But why shouln't this be doable? If this isn't possible, then a lot of the functions in SRL-6 wouldn't work properly

Coh3n

2013-04-04 21:46:19

From: Zyt3x
But why shouln't this be doable? If this isn't possible, then a lot of the functions in SRL-6 wouldn't work properly
Huh? All the functions in SRL-6 work properly.

masterBB

2013-04-05 06:07:09

From: Zyt3x
But why shouln't this be doable? If this isn't possible, then a lot of the functions in SRL-6 wouldn't work properly


Y := Copy(X, 0, 1); // Creates a new copy of X.

where 0 is the starting index
and 1 is the amount of indexes to be copied.

xtrapsp

2013-04-05 06:21:14

Am I correct in thinking this is a 'language' you have written? Based on Pascal?

Olly

2013-04-05 10:49:56

From: xtrapsp
Am I correct in thinking this is a 'language' you have written? Based on Pascal?


here:

interpreter written in FPC/Delphi with a Pascal-like syntax

nielsie95

2013-04-05 10:50:27

From: Zyt3x
@nielsie95; could you make it possible to make functions only work with type variables? i.e a function to check if "self" is a type variable (and not an integer or string) or whatever

This is something I've wanted to fix. It requires static type functions and is harder to implement than I initially hoped.

From: Ollybest
@nielsie95

Comparing TPoints would be small but nice, something this throws this.

 if result <> point(-1, -1) then
debug('woot');


Exception in Script: Operator "cmp_NotEqual" not compatible with types at line 93, column 14

Would be nice, but does not have very high priority for me :)

From: tealc
I was messing around with pointers. I noticed adding and subtracting from pointers does the same thing, but dec(^Integer) and inc(^Integer) don't do the same thing. Is it supposed to be like that.




program new;

var
c,d: Integer;
b,e: ^Integer;

begin

c := 69;
b:=@c;
e:=@c;

d:=random(1000);
e:=e+8*d;
b:=b-8*d;

if(e=b) then writeln('true'); //its always true


end.

When I do something similar with strings I get a "Exeption in script: runtime error: "access violation"" that causes simba to stop responding and I have to stop the program.

Seems like a bug indeed; It looks like Minus actually does Plus for pointers! :pinch:


From: Zyt3x
Getting some really weird bugs here…
var
S : String;
I := 3;

begin
S := toStr(I);
writeLn(S + '-', toStr(I));
end.
This returns -3 instead of 3-3, as it should.

E: TEMP-SOLUTION: Using intToStr() instead works just fine.

Thanks, does indeed look like a bug!


From: Zyt3x
I found another bug.
Assigning one array of whatever (X : array of a) to another array of the same whatever (Y : array of a), causes the second array (Y) to act as a pointer to the first array (X):
type
a = record
b, c : String;
end;
aArr = array of a;

var
X, Y: aArr;

begin
setLength(X, 1);
setLength(Y, 1);
X[0].b := 'Hoi';
X[0].c := 'Dar';
Y := X; // Creates a new copy of X.
X[0].c := 'Bro'; // Change variables c in X only.
writeLn(X, Y); // Output: [{B = Hoi, C = Bro}][{B = Hoi, C = Bro}]
// Result: Both X and Y are changed, even though we only wanted to change X.
end.

E: TEMP-SOLUTION: Assigning and changing variables one by one works. Y[0].b := X[0].b; Y[0].c := X[0].b; Output: [{B = Hoi, C = Bro}][{B = Hoi, C = Dar}]
E2: The TEMP-SOLUTION I posted earlier does not work with more complicated types, though… Tested it on my vCard parser and it does not seem to do the trick.

This is actually as designed and is how it works in Pascal. As MasterBB noted, y := Copy(X); should do the job.

Gu3st...

2013-04-06 19:24:56

From: Coh3n
Huh? All the functions in SRL-6 work properly.
No, we have to update all .swap functions.
@nielsie95; thanks :)

nielsie95

2013-04-07 08:21:34

From: Zyt3x
@nielsie95; could you make it possible to make functions only work with type variables? i.e a function to check if "self" is a type variable (and not an integer or string) or whatever

Had a commit pending since January 4th that addresses this issue. Pushed it now. It's a temporary fix, though, and only at runtime. You can still call the function, but self is undefined. Enable assertions to get a nice exception.


From: Zyt3x
Getting some really weird bugs here…
var
S : String;
I := 3;

begin
S := toStr(I);
writeLn(S + '-', toStr(I));
end.
This returns -3 instead of 3-3, as it should.

E: TEMP-SOLUTION: Using intToStr() instead works just fine.

Should be fixed now :)

From: tealc
I was messing around with pointers. I noticed adding and subtracting from pointers does the same thing, but dec(^Integer) and inc(^Integer) don't do the same thing. Is it supposed to be like that.

When I do something similar with strings I get a "Exeption in script: runtime error: "access violation"" that causes simba to stop responding and I have to stop the program.

Should be fixed now :)

From: Zyt3x
No, we have to update all .swap functions.
@nielsie95; thanks :)

Did you know Lape also has a general swap function?

Coh3n

2013-04-07 09:53:39

From: Zyt3x
No, we have to update all .swap functions.
Oh I thought you were talking about actual core functions, not wrappers or types.

Gu3st...

2013-04-08 04:27:14

From: nielsie95
Did you know Lape also has a general swap function?
Does it also have a general append function? It didn't when I first made the functions, you see :p

Coh3n

2013-04-08 10:55:12

From: Zyt3x
Does it also have a general append function? It didn't when I first made the functions, you see :p
Not sure about append, but there's a general delete() function that probably wasn't there when you wrote the SRL-6 functions.

Olly

2013-04-08 11:22:48

From: Coh3n
Not sure about append, but there's a general delete() function that probably wasn't there when you wrote the SRL-6 functions.


and insert :)

Dgby714

2013-04-09 05:17:30

Append = Insert with last option omitted.

Btw, PS now also has these functions in the latest dev Simba. =)

Gu3st...

2013-04-09 10:25:41

Great work, @Dgby714; :) <3

Brandon

2013-08-12 04:15:57

Since I do not know where to post this.. I'm going to put it here:


var
Str: String;
Ptr: ^Char;
begin
Str := 'Hello World';

Ptr := @Str[0];
writeln(Ord(Str[0]));
Ptr^ := #3; //Should not be able to change the string pointer.
writeln(Str); //Access violation.
end.

This byte determines the length of a string and accessing it through a pointer and being able to change it messes it up. You aren't even supposed to be able to access the first byte of a string by any means other than doing Ord and Length.

masterBB

2013-08-12 04:53:14

The String type no longer uses the first Byte for the length. I believe it is always 0.

e:
If you look at the structure of a string, this is not unexpected. Editing the String or shortString can easily be done like this: Str[1] := 'B';

But Str[0] := 'B'; will simply give an access violation

For the shortString Str[0] := 'B'; will simply set the array at an length of B.

I don't think this is unexpected behaviour in my opinion. But I do think it is odd that the first element of an string will return an access violation… Not really userfriendly.

var
Str: String;
Ptr: ^Char;
begin
Str := 'Hello World';

Ptr := @Str[0];
writeln(Ord(Str[0]));
(Ptr+1)^ := 'B';
writeln(Str);
end.

Brandon

2013-08-12 05:45:46

From: masterBB
The String type no longer uses the first Byte for the length. I believe it is always 0.

e:
If you look at the structure of a string, this is not unexpected. Editing the String or shortString can easily be done like this: Str[1] := 'B';

But Str[0] := 'B'; will simply give an access violation

For the shortString Str[0] := 'B'; will simply set the array at an length of B.



What are you talking about.. The first byte is the length of the string. The example is a working example. I wasn't trying to edit the string. I was trying to show that Lape allows you to access the first byte in a string through pointers but not through subscript.

The examples work if you run both of them. The shortstring still stores the length of the string in the first byte. The longstring stores it as null but changing it from null gives an access violation only when printing the string itself. You can change it to null and it works fine.

Simply do:


var
Str: String;
Begin
...
...
Ptr^ := #0;
writeln(Str); //works fine as long as the first byte is null aka #0. Any other value is access violation.
End;

For short strings this is not the case. For short strings, you are actually changing the stored length of the internal string. You aren't supposed to be able to do that at all since the string itself is not such a length. You can even print it like so:


var
Foo: ShortString;
begin
Foo := 'Hello';
writeln(Ord(Foo[0])); //prints the length of Foo.
end.

Changing index 0 via a pointer will change the length of the short string. You can access index 0 of the long string via a pointer just fine.

However, for long strings you cannot change or access index 0 via the subscript operator. I'm pretty sure that is a bug. Since the implementation of the subscript operator in any language uses a pointer + offset of the index to access any element of the array. Offset 0 is inaccessible via the subscript but is accessible via the pointer. Shouldn't be allowed at all. Strings in pascal are always indexed starting at 1. The index 0 is never to be accessed. Short strings always index at 0 but their values start at 1.


It's like saying you can access index 0 of an array only through a pointer but not through the subscript operator. It's inconsistent for long strings.

masterBB

2013-08-12 06:13:11

From: Brandon
What are you talking about.. The first byte is the length of the string. The example is a working example. I wasn't trying to edit the string. I was trying to show that Lape allows you to access the first byte in a string through pointers but not through subscript.


In the old design of pascal the first byte was the length of the String. But since this limited the length of the String to 256 characters they changed it. Now the first byte is not accesible and always returns 0 in the String type. The ShortString still got the first byte indicating the amount of chars.

So in the ShortString you can access the first Byte. However note that when you change it, it doesn't change the amount of reserved memory like SetLength does. So it is not a great way to enlarge a ShortString with it.

Brandon

2013-08-12 06:32:42

From: masterBB
In the old design of pascal the first byte was the length of the String. But since this limited the length of the String to 256 characters they changed it. Now the first byte is not accesible and always returns 0 in the String type. The ShortString still got the first byte indicating the amount of chars.

So in the ShortString you can access the first Byte. However note that when you change it, it doesn't change the amount of reserved memory like SetLength does. So it is not a great way to enlarge a ShortString with it.



:S You repeated what I said :S

K let me explain again why this is a "BUG".. Perhaps I'll remove the shortstring example if it is confusing.

Operators are implemented as follows.

char* Container = new char[this->Length]; //A string holding length chars.

..
..
..
..

char& string::operator [](int Index) //Index operator's implementation
{
assert(Index >= 0 && !this->Length);
return *(Container + Index); //Access Index via pointer + Offset.
}

const char& string::operator [](int I) const //Const Index operator's implementation
{
assert(I >= 0 && !this->Length);
return *(Container + Index); //Access Index via pointer + Offset.
}

In other words, the subscript operator is supposed to be equivalent to that of the pointer operations when the compiler is finished all its optimizations. If the pointer can access index 0 and print it just fine simply by doing:


Ptr := @Str[0];
writeln(Ptr^); //works fine..

writeln(Str[0]); //does not work.. access violation..


Ptr^ := #0; //set to null..
writeln(Ptr^); //prints fine..

Ptr^ := #13; //set to anything other than null..
writeln(Ptr^); //access violation..

Str[0] := #0; //does not work.. access violation..
Str[0] := #13; //does not work.. access violation..

Then obviously the subscript operator's logic is messed up if it cannot do the same. If the subscript operator is fine, then the pointer arithmetic should throw access violation. Something is wrong with one of those two arithmetic operations no matter how you look at it.


And back to my original post quoted below:


I wasn't trying to edit the string. I was trying to show that Lape allows you to access the first byte in a string through pointers but not through subscript.

It's like saying you can access index 0 of an array only through a pointer but not through the subscript operator. It's inconsistent for long strings.


The only valid way that this is not a bug is if the nielsie's assertion for the operator starts at 1. If so, then why?

masterBB

2013-08-12 07:10:50

From: Brandon

Ptr := @Str[0];
writeln(Ptr^); //works fine..

writeln(Str[0]); //does not work.. access violation..


Ptr^ := #0; //set to null..
writeln(Ptr^); //prints fine..

Ptr^ := #13; //set to anything other than null..
writeln(Ptr^); //access violation..

Str[0] := #0; //does not work.. access violation..
Str[0] := #13; //does not work.. access violation..

Then obviously the subscript operator's logic is messed up if it cannot do the same. If the subscript operator is fine, then the pointer arithmetic should throw access violation. Something is wrong with one of those two arithmetic operations no matter how you look at it.


Ah, I think I know where we misscomunicate. I simply looked at different results:

var
Str: String;
StrPtr: ^Char;

SStr: ShortString;
SStrPtr: ^Char;

begin
SStr := 'Hello World';

SStrPtr := @SStr[0];
writeln(Ord(SStr[0])); //Always returns the length
writeln(Ord(SStrPtr^)); //Idem dito

Str := 'Hello World';

StrPtr := @Str[0];
writeln(Ord(Str[0])); //Always returns 0, since it no longer indicates the length
writeln(Ord(StrPtr^)); //Idem dito

SStrPtr^ := [URL=http://villavu.com/forum/usertag.php?do=list&action=hash&hash=5]#5[/URL] ; //sets the length
SStr[0] := [URL=http://villavu.com/forum/usertag.php?do=list&action=hash&hash=6]#6[/URL] ; //sets the length

StrPtr^ := [URL=http://villavu.com/forum/usertag.php?do=list&action=hash&hash=5]#5[/URL] ; //tries to access a not used Byte <- No error, but breaks the String
Str[0] := [URL=http://villavu.com/forum/usertag.php?do=list&action=hash&hash=6]#6[/URL] ; //idem dito <- No error, but breaks the String

writeln(SStr); //no error
writeln(Str); //error
end.

Your whole issue is at the Str[0] := and the StrPtr^ := part. Well for me they work the same. when you set any of those to any vallue other than 0, it will break the string. When the String is broken it will just cause an access violation whatever you do with it. Therefor this piece of code will error at Str[0] := #6 ; But if you swap the two lines it will error at StrPtr^ := #5 ; .

Is that where we not understand each other?

Brandon

2013-08-12 07:27:02

Yes that is where we understand eachother. Also, if index 0 isn't used, why does a non-null value "break" the string.

Edit: I'm not sure how it works for you but not me :S Simply doing any string[0] gives me access violation. In PS it gives me out of range but lape is just plain access violation.

Edit2: Fixed by updating my Simba. Weird :S

Edit3: @masterBB; I'd also like you to re-visit this thread: http://villavu.com/forum/showthread.php?t=105107 <– It did apply to pascal script. Not sure about lape though but.. just visit it.

If you are lazy then just try:

var
Str: String;

begin
Str := 'hello';
//SetLength(Str, 250); //without this, it will throw error in PS. No need in lape :S. Terror in a for-loop. Just view the thread above.
Str[200] := 'b';
writeln(Length(Str));
writeln(Str);
end.

masterBB

2013-08-12 08:42:05

From: Brandon
If you are lazy then just try:

var
Str: String;

begin
Str := 'hello';
//SetLength(Str, 250); //without this, it will throw error in PS. No need in lape :S. Terror in a for-loop. Just view the thread above.
Str[200] := 'b';
writeln(Length(Str));
writeln(Str);
end.


There is no range checking in lape. If you simply use out of range elements you will edit random pieces of memory(limited to the simba memory space, you can't crash windows).

slacky

2013-08-12 09:25:20

From: masterBB
There is no range checking in lape. If you simply use out of range elements you will edit random pieces of memory(limited to the Simba memory space, you can't crash windows).

That would be temporary solvable by running Lape/the script as it's own process(?). That way only the script can be crashed, and only the memory that the script uses can be edited? Should be doable, but might complicate things…

Brandon

2013-09-18 16:55:36

How can I determine the type of X in the following untyped variable:


procedure Foo(var X);
Begin
writeln(sizeof(X)); //Can't..
writeln(typeof(X)); //Can't..
End;

var
X: Integer;
begin
X := 10;
Foo(X);
end.

Without the two comment lines, it compiles just fine.. I can cast X to integer and it works but I want to know the type of X.


I'm trying to do an array of absolutely anything..


type AList = record
X; //Can't.. Why can we only do it with functions :S
end;

masterBB

2013-09-18 17:23:38

You mean like Variant?

Brandon

2013-09-18 20:40:01

From: masterBB
You mean like Variant?


No because Variant can't be "anything". Variant has a list of specific types that it can take.

Daniel

2013-09-19 03:18:09

From: Brandon
How can I determine the type of X in the following untyped variable:


procedure Foo(var X);
Begin
writeln(sizeof(X)); //Can't..
writeln(typeof(X)); //Can't..
End;

var
X: Integer;
begin
X := 10;
Foo(X);
end.

Without the two comment lines, it compiles just fine.. I can cast X to integer and it works but I want to know the type of X.


I'm trying to do an array of absolutely anything..


type AList = record
X; //Can't.. Why can we only do it with functions :S
end;


Hmm, one would assume VarType. However for some reason in the Simba build that I am using, that whenever I try to pass that untyped argument it seems to raise "Cannot invoke identifier" :-/ Using it within conditional statements is fine, though… so you could like have a hellish number of if..then statements just to identify the type :p

Brandon

2013-09-19 13:58:02

From: Daniel
Hmm, one would assume VarType. However for some reason in the Simba build that I am using, that whenever I try to pass that untyped argument it seems to raise "Cannot invoke identifier" :-/ Using it within conditional statements is fine, though… so you could like have a hellish number of if..then statements just to identify the type :p


Yeah I was getting the same thing.

Can't test what type it is, it will throw access violation error and try catching it can't work for that.

Example:


procedure Foo(var X);
begin
writeln(Integer(X)); //works fine..
writeln(String(X)); //all hell will break loose.
end;

var
X: Integer;
begin
Foo(X);
end.

and we can't do something like.. if (X = Integer) then.. There's no comparison for it.

Off topic:
We cannot overload operators so comparison of TPoints is a no-no. We have to compare TPoint.X and TPoint.Y unless that is committed into Simba itself at a later time or else write a Tpoint.Equals(TP: TPoint): Boolean; function..

Coh3n

2013-09-19 20:30:06

From: Brandon
Off topic:
We cannot overload operators so comparison of TPoints is a no-no. We have to compare TPoint.X and TPoint.Y unless that is committed into Simba itself at a later time or else write a Tpoint.Equals(TP: TPoint): Boolean; function..
There's a TPoint.equals() in SRL-6. lib/utilities/types/tpoint.simba I believe. If you want to use it.

Daniel

2013-09-20 02:31:15

From: Brandon

and we can't do something like.. if (X = Integer) then.. There's no comparison for it.


I know that. I was referring to checking if casting to another type and checking if that were equal to the original. However, in my extended testing this won't actually work. :(

riwu

2013-09-20 08:18:35

From: Brandon
How can I determine the type of X in the following untyped variable:


procedure Foo(var X);
Begin
writeln(sizeof(X)); //Can't..
writeln(typeof(X)); //Can't..
End;

var
X: Integer;
begin
X := 10;
Foo(X);
end.

Without the two comment lines, it compiles just fine.. I can cast X to integer and it works but I want to know the type of X.


I'm trying to do an array of absolutely anything..


type AList = record
X; //Can't.. Why can we only do it with functions :S
end;

I think it's because within the method Foo(), it has no information about the type of X at compile time. So unless we deliberately suppress this compile time check? (unless it has no type info of the argument passed at run time as well)

Dgby714 made the following code to compare any type:

function Equals(var L, R; Size: UInt32): Boolean;
{$IFNDECL PUInt8}
type
PUInt8 = ^UInt8;
{$ENDIF}
var
I: UInt32;
L_P := PUInt8(@L);
R_P := PUInt8(@R);
begin
for I := 0 to Size - 1 do
if not (L_P[I]^ = R_P[I]^) then
Exit;
Result := True;
end;

Brandon

2013-09-20 09:25:48

From: riwu
I think it's because within the method Foo(), it has no information about the type of X at compile time. So unless we deliberately suppress this compile time check? (unless it has no type info of the argument passed at run time as well)

Dgby714 made the following code to compare any type:


Seeing as the function compares the bytes of a type via the unsigned char, it still fails:


function Equals(var L, R; Size: UInt32): Boolean;
{$IFNDECL PUInt8}
type
PUInt8 = ^UInt8;
{$ENDIF}
var
I: UInt32;
L_P := PUInt8(@L);
R_P := PUInt8(@R);
begin
for I := 0 to Size - 1 do
if not (L_P[I]^ = R_P[I]^) then
Exit;
Result := True;
end;

type PUint8 = ^Uint8;
var
L: String;
R: Array of Char;
L_P, R_P: PUint8;
begin
L := '1';
R := ['1'];

L_P := @L;
R_P := @R;
writeln(L_P[0]^);
writeln(R_P[0]^);

writeln(Equals(L, R, Length(L)));
end.

Still, he's assuming that the type can be casted to uint8_t (unsigned char). Secondly, if an array type is passed, he's de-referencing the wrong address.

Example:

L_P := @L[1]; //First index must be 1.
R_P := @R[0]; //Must have the index operator.


Why? Because @R is the address of the array itself. @R[0] is the index of the very first element. However for strings, L[1] is the index of element 0.

So yes.. there's so many flaws in that equals function that it won't work for "Every" type. For more complex types like:

type Foo = record
X: Integer;
Y: String;
end;

It would fail..

It also allows you to compares two different types which is bad..

Still doesn't determine what type something is.

Kevin

2013-09-20 12:09:48

As for a comment in relation to a generic Equals method, does Lape allow for reflection so we could simply iterate over each element of an object (handling records or lists) and then compare base objects at the bit-wise level?

nielsie95

2013-09-20 13:46:47

The untyped parameter does not have any type info whatsoever. See the following links for more information:
http://docwiki.embarcadero.com/RADStudio/XE4/en/Parameters_%28Delphi%29#Untyped_Parameters
http://pages.cs.wisc.edu/~rkennedy/untyped

You cannot compare it with dynamicly typed programming languages such as JavasScript or Python, this is much more low level. For SRL, most of the time it's not very interesting.
Lape does currently not support type reflection.

riwu

2013-09-20 21:17:26

From: Brandon
Seeing as the function compares the bytes of a type via the unsigned char, it still fails:


function Equals(var L, R; Size: UInt32): Boolean;
{$IFNDECL PUInt8}
type
PUInt8 = ^UInt8;
{$ENDIF}
var
I: UInt32;
L_P := PUInt8(@L);
R_P := PUInt8(@R);
begin
for I := 0 to Size - 1 do
if not (L_P[I]^ = R_P[I]^) then
Exit;
Result := True;
end;

type PUint8 = ^Uint8;
var
L: String;
R: Array of Char;
L_P, R_P: PUint8;
begin
L := '1';
R := ['1'];

L_P := @L;
R_P := @R;
writeln(L_P[0]^);
writeln(R_P[0]^);

writeln(Equals(L, R, Length(L)));
end.

Still, he's assuming that the type can be casted to uint8_t (unsigned char). Secondly, if an array type is passed, he's de-referencing the wrong address.

Example:

L_P := @L[1]; //First index must be 1.
R_P := @R[0]; //Must have the index operator.


Why? Because @R is the address of the array itself. @R[0] is the index of the very first element. However for strings, L[1] is the index of element 0.

So yes.. there's so many flaws in that equals function that it won't work for "Every" type. For more complex types like:

type Foo = record
X: Integer;
Y: String;
end;

It would fail..

It also allows you to compares two different types which is bad..

Still doesn't determine what type something is.

Array comparing is done with: Equals(arr1[0], arr2[0], SizeOf(arr1) * Length(arr1)), and similarly, for strings, Equals(str1[1], str2[1], SizeOf(str1) * Length(str1)).

We would have to check the type and length before calling the function, like:
equal:= (VarType(A) = varType(B)) and (Length(A) = Length(B)) and Equals(A, B, SizeOf(A))

Tedious and doesn't work for complex types like you said, so i guess we will have to create .equals functions for all the common types and arrays.

Dgby714

2013-09-21 01:48:16

From: Brandon
Seeing as the function compares the bytes of a type via the unsigned char, it still fails:
Still, he's assuming that the type can be casted to uint8_t (unsigned char). Secondly, if an array type is passed, he's de-referencing the wrong address.

Why? Because @R is the address of the array itself. @R[0] is the index of the very first element. However for strings, L[1] is the index of element 0.

So yes.. there's so many flaws in that equals function that it won't work for "Every" type. For more complex types like:

It would fail..

It also allows you to compares two different types which is bad..

Still doesn't determine what type something is.


That method was written to be used behind the scenes.

It works fine on array types as long as you pass the first item. (Seeing as array items are sequential in memory)

Also, anything you give it can be type-casted to a unsigned character.

Yes, it will not work for some complex types. Namely records with strings/arrays.

function TIntegerArray.Equals(Arr: TIntegerArray): boolean;
begin
Result := (Length(Self) = Length(Arr)) and Equals(Self[0], Arr[0], SizeOf(Self[0]) * Length(Self));
end;

This one is completely useless, but meh, here…
function string.Equals(Arr: string): boolean;
begin
Result := (Length(Self) = Length(Arr)) and Equals(Self[1], Str[1], SizeOf(Self[1]) * Length(Self));
end;

Maybe we should write this as a magic function in Lape? Would allow me to use the proper compares.

Brandon

2013-09-21 02:00:16

From: Dgby714

If we write Compare methods for the base types, complex types are easy =/
Maybe we should write this as a magic function in Lape?


Hmm. Did not think about that case (the passing array index to the function). However, I won't assume that you can just type case all types to PUint8. While that is technically true, it isn't safe for all types especially that of a pointer. Yes, the addresses as bytes would match but Equals would really only be useful if only the content was matched and not the type pointed to.

It'd be most beneficial to be able to figure out what type X is and to be able to instantiate a type that is the same as X.. Otherwise, there isn't much that you can do with "X" as an un-typed variabled. I'm not exactly sure the benefits of X as is without the features mentioned.

Dgby714

2013-09-21 04:19:06

From: Brandon
Hmm. Did not think about that case (the passing array index to the function). However, I won't assume that you can just type case all types to PUint8. While that is technically true, it isn't safe for all types especially that of a pointer. Yes, the addresses as bytes would match but Equals would really only be useful if only the content was matched and not the type pointed to.

It'd be most beneficial to be able to figure out what type X is and to be able to instantiate a type that is the same as X.. Otherwise, there isn't much that you can do with "X" as an un-typed variabled. I'm not exactly sure the benefits of X as is without the features mentioned.


He wanted a generic method that worked with "most" types. That is what I wrote.

You can cast any type to PUInt8, tho yes it is useless on Pointer types (This includes arrays and string), that is the exception.

Tech, this Equals method does exactly what it should, even with Pointer types.

Gu3st...

2013-10-21 23:17:36

From: nielsie95
Multithreading isn't really part of the engine. It could be implemented in several ways, just like it could be implemented in Pascal Script in several ways. I don't think it's that important, though. I'd rather get SRL working so that there's a chance people might actually test this ;)
Could you/we push this farther up on the to-do list now then? :D Now that we've released SRL-6 Beta?

Gu3st...

2013-12-12 21:24:57

@nielsie95; Could it be possible to create a case-statement with different types of variable types?
{$ContinueCase ON}
type
TSettings = record
placeholder:integer;
end;
TDatabase = record
settings : TSettings;
end;

function TSettings.loadFromFile(const path : String): Boolean;
begin
result := True;
end;

function TDatabase.loadFromFolder(const path : String): Boolean;
var
files : TStringArray;
I : Integer;
begin
result := True;
files := getFiles(path, 'dob');
for I := 0 to high(files) do
case files[I] of
'settings': continue(settings.loadFromFile(path + files[I] + '.dob')); // Returns True
True: writeLn('Successfully loaded file: ' + files[I]);
False:
begin
result := False;
writeLn('ERROR: Failed loading file: ' + files[I]);
end;
else
writeLn('File unsupported: ' + files[I]);
end;
end;

begin
end.

E: I know I can use result for this instead of continue, but I'd like to do it this way. It looks neater in my opinion :)
E2: Could you explain sets for me? Also, is loose syntax possible with types?
E3: If not with types, then how far up on the to-do list is classes?

Gu3st...

2013-12-13 19:24:53

BUMP! Justified triple-post. This thread needs to be seen soon, taking all my ideas into consideration. :p

Is it be possible to assign constants to type records?
type TTest = function(params : String): Boolean;

const
TTest.oneFunctionPossibility = @possibilityOne;
TTest.someOtherFunctionPossibility = @possibilityTwo;

procedure TTest.setFunction(const f : TTest);
begin
self := @f;
end;

var
Test : TTest;

begin
Test.set(TTest.oneFunctionPossibility);
someOtherVariable := possibilityOne('Hello World!');
end;
I want to out the functions that oneFunctionPossibility refers to to other causes than just for TTest; I also want to use the functions for other things, like assigning the resulting value of "Hello World!" to someOtherVariable.

Brandon

2013-12-13 20:05:08

From: Zyt3x
…


No clue what you're asking but I understand you can make constant records.


type TTest = function(params : String): Boolean;

function p(params: String): Boolean
begin
writeln('p func');
end;

const
T : TTest := (@p);

begin
//T := @P; Error. Cannot assign to a constant.
T('');
end.


And for the case statement, why not just nest it?


{$ContinueCase ON}

type
TSettings = record
placeholder:integer;
end;

TDatabase = record
settings : TSettings;
end;

function TSettings.loadFromFile(const path : String): Boolean;
begin
result := True;
end;

Function Test: Boolean;
var
I: Integer;
S: TSettings;
Files: TStringArray;
Begin
For I := 0 To High(Files) Do
Begin
Case Files[I] Of
'Settings':
Case S.LoadFromFile(Files[I]) Of
True: begin end;
False: begin end;
End;
End;
End;
End;

I don't think you can call "Continue" on a non-const expression.

Gu3st...

2013-12-13 20:53:56

From: Brandon
No clue what you're asking but I understand you can make constant records.


type TTest = function(params : String): Boolean;

function p(params: String): Boolean
begin
writeln('p func');
end;

const
T : TTest := (@p);

begin
//T := @P; Error. Cannot assign to a constant.
T('');
end.


And for the case statement, why not just nest it?


{$ContinueCase ON}

type
TSettings = record
placeholder:integer;
end;

TDatabase = record
settings : TSettings;
end;

function TSettings.loadFromFile(const path : String): Boolean;
begin
result := True;
end;

Function Test: Boolean;
var
I: Integer;
S: TSettings;
Files: TStringArray;
Begin
For I := 0 To High(Files) Do
Begin
Case Files[I] Of
'Settings':
Case S.LoadFromFile(Files[I]) Of
True: begin end;
False: begin end;
End;
End;
End;
End;

I don't think you can call "Continue" on a non-const expression.
Thanks for the constants help, but the "nested case" isn't anything near what I need; you didn't quite understand the point :P
It's possible to do with two case statements called after eachother, but that takes up extra lines of code, I just wanted to be able to case it in one case statement instead of expanding the single-line for-loop into a multiple lined for-loop.

      True: writeLn('Successfully loaded file: ' + files[I]);
False:
begin
result := False;
writeLn('ERROR: Failed loading file: ' + files[I]);
end;
This would work for all files added, "settings" is just one of the many file names that I want to add to that case-statement, i.e "user" or "downloaded" or whatever.

E: Actually, that constant thing isn't what I wanted either. I wanted to add the constant to the type function itself.
const
TTest.testFunction : TTestFunction := @testFunction;

Brandon

2013-12-13 22:04:22

From: Zyt3x
Thanks for the constants help, but the "nested case" isn't anything near what I need; you didn't quite understand the point :P..

E: Actually, that constant thing isn't what I wanted either. I wanted to add the constant to the type function itself.
const
TTest.testFunction : TTestFunction := @testFunction;



Are you sure it wouldn't work in a single statement?

Example:

Function Test: Boolean;
var
I: Integer;
S: TSettings;
Files: TStringArray;
Begin
For I := 0 To High(Files) Do
Begin
Case Files[I] Of
'Settings', 'Meh', 'Bleh', 'Downloads', 'DontKnow', 'etc': //Just comma separate them..
Case S.LoadFromFile(Files[I]) Of //same as an if statement :l
True: begin end;
False: begin end;
End;
End;
End;
End;

Like in the above. It's comma separated. Any file you specify is done in that single case statement. Is that what you mean?

As for the constants, I still don't know what you mean.. Are you trying to make a static constant? For example, all instances of Test will have the same function assigned to it and be constant at the same time?

The reason I ask this is because what you just said sounds like:

a: a const object function

function TTest.somefunc(param: String): Boolean
begin
end;

b: a static/constant object function (accessed through TTest.func instead of TTestInstance.func.. Not possible in Lape afaict.)


type
TTest = record
func: const TTestFunction = @P; //equivalent to static constant function.
func2: TTestFunction; static; //just static so it can be changed and all object instances see the change.
func3: const TTestFunction = @P; static; //static and cannot be changed.
end;

var
SomeTTestInstance: TTest;
begin
SomeTTestInstance.func('hey'); //constant but not static. Required object instance.

//static but not constant. Requires no instance and can be changed.
TTest.func2 := @P;
TTest.func2 := @P2;
TTest.func2('hey');

//static and constant. Required no instance and can NOT be changed.
TTest.func3('hey');
end;

//None of the above is possible in Simba except for the first. In that case, see option a.

c: const object instance function. (what I already gave you in the previous post)

Gu3st...

2013-12-15 07:35:07

The case-block wont help because I want to load each file (settings.file, downloaded.file, uploaded.file, bleh.file) into each variable of it's own; settings.file will be loaded in the type TSettings while downloaded+uploaded will be in the type TDatabase but in different variables.

As for the function pointer part: Option B is what I want implemented.

Thanks for clearing any misunderstandings in my post :)

nielsie95

2014-08-15 14:12:07

Fixed a lot of bugs this week, although it might take some time before they are available in Simba:

  • Constant parameters were secretly not constant, now they are (added FPC's constref parameters instead) (#22)
  • Initialization of variable with a method address (#23)
  • Declaring a ToString on a type could cause an access violation (#25)
  • Inline var declaration in for-loop in loose syntax mode (#29)
  • Better error message when using a random colon (#32)
  • Boolean comparison (similar to Slacky's fix)
  • Stack overflow with expressions not used in an assignment (reported by Slacky)
  • Memory leak after calling an FFI imported functions that returned a reference counted type; plugin functions returning an array, for example (reported by Slacky)
  • Constant dynamic arrays are now constant static arrays (https://villavu.com/forum/showthread.php?t=109440)
  • Better handling of overloaded methods on types and subtypes (https://villavu.com/forum/showthread.php?t=108636)
  • Local parameters and variables now have precedence over fields (https://villavu.com/forum/showthread.php?t=108446).

If you find any bugs (or suspected bugs), don't hesitate to open an issue, create a thread in this forum, post in in this thread, or message me!
Also, if you haven't already, make sure you take a look at Brandon's introduction tutorial. It explains a lot of cool features :)

So, what problem(s) do you currently face with Lape? What would be the most wanted feature to implement?

slacky

2014-08-15 14:48:59

From: nielsie95
Fixed a lot of bugs this week, although it might take some time before they are available in Simba …

Great job!! You really managed to do all that in quite a short period of time :P

I guess the most wanted feature at the moment would be Property. I guess @Olly would agree, as he been bugging me about the lack for some time, he almost manages to irritate me.


Bugs I remember right now:
  • Operator-priority bug (comparing to FPC/Delphi), both should write 16777215:

  • begin
    WriteLn( $FF or $FF shl 8 or $FF shl 16 ); //Wrong - Should yield the same as the one below
    WriteLn( $FF or ($FF shl 8) or ($FF shl 16) ); //Correct
    end.
    Another example, each of these should write 255:

    var c:Int32 = $FFFFFF;
    begin
    WriteLn( c and $FF );
    WriteLn( c shr 8 and $FF );
    WriteLn( c shr 16 and $FF );
    end.
  • Missing/bad error-handling:

  • begin
    WriteLn( True * 6 );
    end.
    » Exception in Script: Unknown Run-Time error : 202
I do believe that there exists a few more bugs, I just can't remember them right now.


Other features that could be nice (but might require a lot of work):
  • Range-check (array).
  • Units | unit-ish system -> Allows modules to co-exist, even tho they contain methods with same names.
  • Access modifiers: Private / Protected / Public for Advanced records
  • Maybe allow indexing in method-calls - Could be used as an alternative to passing empty expressions for default params:

  • procedure MyTest(a:Int32=0; b:Int32=0; c:Int32=0);
    begin WriteLn([A,B,C]); end;

    begin
    MyTest(B:=10; A:=5);
    end.
  • Operator overload would always be nice to have.
  • Smarter array initialization within a (overloaded) method-call:

  • procedure MyTest;
    begin end;

    procedure MyTest(a:TVariantArray); overload;
    begin WriteLn(a); end;

    begin
    MyTest([0,1,2,3,4]);
    end.
    Will fail, as it doesn't know which method to call, as the array will now default in Array of Int32.
  • Absolute-keyword (http://docwiki.embarcadero.com/RADStudio/XE4/en/Variables#Absolute_Addresses)
  • For .. In-loop -> Looping over Static Array, Strings, maybe even Dynamic Arrays.
Oh my what a long list… Don't think of am as requests, I am simply mentioning them.



*makes room for future edit, and additions*

Brandon

2014-08-15 15:23:26

From: slacky

[*]Range-check (array).



No.. please no.. Why do we need this ={
I have a tendency to export arrays from plugins by modifying the reference count. The same trick can be used for linked-lists. I'd agree with the class modifiers though.

I like Lape's pointers tbh.. If I had to request a feature, it'd be const pointer. Such that the data pointed to cannot be changed.

Example, I could return a const pointer to some data and it would guarantee that the user can only read it and not change any of the data the pointer points to.

That would be neat. OR even a const pointer that once assigned cannot be changed. Might be some work to implement these though so I leave it as an idea instead of a request.

slacky

2014-08-15 15:27:27

From: Brandon
No.. please no.. Why do we need this ={
I have a tendency to export arrays from plugins by modifying the reference count. The same trick can be used for linked-lists. I'd agree with the class modifiers though.

A compiler directive to disable/enable it would be needed.
Why it's needed? Because of Simbas userbase.

riwu

2014-08-15 20:07:25

From: slacky
A compiler directive to disable/enable it would be needed.
Why it's needed? Because of Simbas userbase.

I second this. As an inexperienced user and not being particularly meticulous, i spent 10min figuring what went wrong with a simple piece of code

pt := Point(gt2[k].Bounds.X2 + 4 + RandomRange(-5, 5), gt2[k].Bounds.Y2 + RandomRange(-5, 5));
copied from somewhere above, changed variable gt to gt2, but completely forgot to change the variable 'k' (which after a loop, holds a value > 50) to '0', and somehow failed to see it despite looking at the code several times….and it could have been identified easily if there's a range check!

nielsie95

2014-08-16 15:24:40

@slacky; I changed the precedence and associativity of some operators to be more like Pascal instead of C, so those expressions should work now. I also fixed the second bug.

I agree range checking would be a useful addition. Properties and access modifiers are not really in line with the current state of type methods, they would only make sense for records. Perhaps I can implement a version of properties where only methods are allowed as getter/setter. Units, operator overloading and for..in are good suggestions, but have a lower priority in my opinion. I don't see the absolute keyword and extended syntax for argument passing happening.

@Brandon; I can see the use for something like that, especially for a scripting language. So basically a pointer type that you cannot dereference?

Thanks for your suggestions :)

Brandon

2014-08-17 20:25:43

From: nielsie95
@slacky; I changed the precedence and associativity of some operators to be more like Pascal instead of C, so those expressions should work now. I also fixed the second bug.

I agree range checking would be a useful addition. Properties and access modifiers are not really in line with the current state of type methods, they would only make sense for records. Perhaps I can implement a version of properties where only methods are allowed as getter/setter. Units, operator overloading and for..in are good suggestions, but have a lower priority in my opinion. I don't see the absolute keyword and extended syntax for argument passing happening.

@Brandon; I can see the use for something like that, especially for a scripting language. So basically a pointer type that you cannot dereference?

Thanks for your suggestions :)


Yup. Just a read only pointer. It's neat for libraries and such. I only found myself looking for such a thing 3 or 4 times but still useful.

slacky

2014-08-18 15:18:37

Some bug reports:
Lape has a new bug which I was unable to trace down, and I am not in the mood today to trace it down, just knows it's raised in this piece of code.
- http://pastebin.com/SEzef3TF
I am sorry that I can't narrow it down any further now.


There exists another (old) bug related to for loops, which causes it to go in to an "eternal" loop:

var B:Byte;
begin
for B:=0 to High(Byte) do WriteLn(B);
end;
Note that B is a byte, so when it reaches max-byte (255) it starts over again.

Brandon

2014-08-18 15:59:17

From: slacky

There exists another (old) bug related to for loops, which causes it to go in to an "eternal" loop:

var B:Byte;
begin
for B:=0 to High(Byte) do WriteLn(B);
end;
Note that B is a byte, so when it reaches max-byte (255) it starts over again.



This is not a bug. This is defined behaviour for unsigned arithmetic..

This is an unsigned arithmetic overflow.


HIGH(Byte) is equivalent to 0xFF(255). The loop specifically says to go from 0 inclusive-to 255. That includes the 255. This is why we iterate Length - 1 except for strings (where the base index is 1).

Equivalent to:

#include <stdio.h>


int main(void)
{
unsigned char B = 0;
for (; B <= 255; ++B)
printf("%u\n", B);
return 0;
}


On the last iteration, it will "wrap-around" and become 0 again. Infinite loop lol.

You can tell that the "to" keyword is inclusive because you can do the same for a word to high(word) and the second to last iteration should print 65535. It will wrap around on the last iteration and voila. Infinite loop again. If you print the last value after the loop, you'll see that it hit 1 above the max if using an integer as the operand.





A 72mb bitmap? What?

Lets add. 72mb rgba bitmap + 144mb integer 2D-matrix + 72mb TPointArray + 72mb TPointList. And this doesn't take into account ALL the allocations made (copies, etc..). Just some.. Could be one of the reasons it crashes is because it doesn't have memory (MAYBE). IIRC, Simba scripts had a limit of 500-700 last time Kasi & I tested large bitmaps.

I emulated some of the allocations of that script and was over 400mb. I terminated it and the memory was NOT freed for obvious reason (thread pre-mature termination).

slacky

2014-08-18 17:45:36

From: Brandon
This is not a bug. This is defined behaviour for unsigned arithmetic..

This is an unsigned arithmetic overflow.


HIGH(Byte) is equivalent to 0xFF(255). The loop specifically says to go from 0 inclusive-to 255. That includes the 255. This is why we iterate Length - 1 except for strings (where the base index is 1).

Equivalent to:

#include <stdio.h>


int main(void)
{
unsigned char B = 0;
for (; B <= 255; ++B)
printf("%u\n", B);
return 0;
}


On the last iteration, it will "wrap-around" and become 0 again. Infinite loop lol.

You can tell that the "to" keyword is inclusive because you can do the same for a word to high(word) and the second to last iteration should print 65535. It will wrap around on the last iteration and voila. Infinite loop again. If you print the last value after the loop, you'll see that it hit 1 above the max if using an integer as the operand.

Open Lazarus (FPC)… write a small application -> add the "bugged" code to it, run the app.. What happens… it stops at 255.
I get your point tho, but that doesn't make it differs any less from how it is in FPC.


From: Brandon

A 72mb bitmap? What?

Lets add. 72mb rgba bitmap + 144mb integer 2D-matrix + 72mb TPointArray + 72mb TPointList. And this doesn't take into account ALL the allocations made (copies, etc..). Just some.. Could be one of the reasons it crashes is because it doesn't have memory (MAYBE). IIRC, Simba scripts had a limit of 500-700 last time Kasi & I tested large bitmaps.

I emulated some of the allocations of that script and was over 400mb. I terminated it and the memory was NOT freed for obvious reason (thread pre-mature termination).

Your math is off, or maybe you are just trowing random numbers in the air.. All in all it uses about 103MB of RAM… this is as you say except for "ALL the allocations made (copies, etc..)"

Let me help you with that math:
Bitmap: (3000*3000 * 4 ) / 1024 / 1024 = 34.3MB
Matrix: (3000*3000 * 4 ) / 1024 / 1024 = 34.3MB
TPA: (4000000 * 8) / 1024 / 1024 = 34.3MB (btw you where just trowing in a random number, as you didn't know the size of the TPA, who does that??)

exp_ImFindColorTolEx .. Will also use some extra RAM.. At worst causng the tpa to be 2x the size of the result (which was about 4mill), before it's cut down, if I remember correctly.. But I don't remember if I wrote it this way right now.. and if it's like that then we are talking about a total of about 137MB used..


Also did I forget to mention that it was a NEW bug? Which means this worked before, and even much larger stuff worked.
Oh wait I did mention that it was a new bug:
Lape has a new bug …



Oh and that Simba memory-limit you are talking about.. it's at about 1.3GB mem used.

Olly

2014-08-18 17:52:00

debate!

Brandon

2014-08-18 18:15:56

From: slacky
Open Dlephi, FPC or what ever pascal-ide… write a small application.. add the "bugged" code to it, run the app.. What happens… it stops at 255
End of discussion.



You math is off, or maybe you are just trowing random numbers in the air.. All in all it uses about 103MB of RAM… this is as you say except for "ALL the allocations made (copies, etc..)"

Let me help you with that math:
Bitmap: (3000*3000 * 4 ) / 1024 / 1024 = 34.3MB
Matrix: (3000*3000 * 4 ) / 1024 / 1024 = 34.3MB
TPA: (4000000 * 8) / 1024 / 1024 = 34.3MB (btw you where just trowing in a random number, as you didn't know the size of the TPA, who does that??)

exp_ImFindColorTolEx .. Will also use some extra RAM.. At worst causng the tpa to be 2x the size of the result (which was about 4mill), before it's cut down, if I remember correctly.. But I don't remember if I wrote it this way right now.. and if it's like that then we are talking about a total of about 137MB used..


Also did I forget to mention that it was a NEW bug? Which means this worked before, and even much larger stuff worked.
Oh wait I did mention that it was a new bug:



Oh and that Simba memory-limit you are talking about.. it's at about 1.3GB mem used.


First off. I was trying to help you but since you are so rude.. Here's how I calculated it (In Lape):


type
RGBA = record
R, G, B, A: Byte;
end;


begin
writeln(sizeof(RGBA) * 3000 * 3000);
writeln(72000000 / (1024 * 1024));
end.


What does it print? Oh that's right.. It doesn't print 38mb. https://www.google.ca/search?q=bytes+to+mb&oq=bytes+to+mb&aqs=chrome..69i57j0l5.1830j0j7&sourceid=chrome&es_sm=93&ie=UTF-8#q=72000000+bytes+to+mb

The number wasn't EXACT. It's from Google's byte to MB calculation. Even then, it wasn't even near 38mb.

And no. I didn't mess up the TPA calculation. I assumed it was the same size as the RGBA record * 2 (for 2 points) for EACH point.

Only thing I messed up was NOT using "packed record" which caused double the size for a DWORD aligned & sized structure (btw which is 4 bytes in every other language and isn't padded as it is in Lape).
You could have asked how I got the numbers in the first place but you didn't. Instead, you curse and assume I'm trying to screw you over.



Lol. The only thing you are right about at this moment is that it is indeed the end of discussion because YOU'RE wrong and there's no simpler way to say it than to show an example:

http://ideone.com/2UHqzA
http://ideone.com/3xkExP


Thus showing FPC's "to" keyword (same as Lape's) is inclusive as I said earlier. The behaviour is DEFINED and that means you were relying on shitty and bugged code before for YOUR mistake. If it wasn't ever inclusive, you'd have never used Length - 1 in your loops. /logic.

With an attitude like yours, that'd be the last time I attempt to help you.

slacky

2014-08-18 18:30:57

From: Brandon
First off. I was trying to help you but since you are so rude.. Here's how I calculated it:


type
RGBA = record
R, G, B, A: Byte;
end;


begin
writeln(sizeof(RGBA) * 3000 * 3000);
writeln(72000000 / (1024 * 1024));
end.


1. Your record is not packed, unlike TRGB32 in Simba, so your RGBA uses 4 extra bytes, hence SizeOf(RGBA) = 8.

type
packed RGBA = record
R, G, B, A: Byte;
end;

begin
WriteLn(SizeOf(RGBA) * 3000 * 3000);
WriteLn(36000000 / (1024 * 1024));
end.

2. The matrix is 3000x3000 of Int32 which is by definition 32 bits (or 4 bytes if you like), hence the name.

My calculations are correct, yours are off as I said.

—

Regarding "rudeness":
It's funny, but I managed to find YOUR post rude. Starting with telling me "This is not a bug", yet it doesn't act as it does in FPC. It may or may not be a bug, but that actually depends on how neils looks at it. If that behavior was intended, then it's clearly not a bug, if not, then it can be look up on as a bug.

Second part you start of with "A 72mb bitmap? What?", then comes up with some numbers which are off, all that to verify that I am most likely wrong about this?


and guess what, I said it was a NEW bug.. which also implies it worked before.

Also, I am not here for your "help", I reported what I was pretty sure was related to a bug, and I still am.

Brandon

2014-08-18 18:34:29

From: slacky
1. Your record is not packed, unlike TRGB32 in Simba, so your RGBA uses 4 extra bytes, hence SizeOf(RGBA) = 8.

type
packed RGBA = record
R, G, B, A: Byte;
end;

begin
WriteLn(SizeOf(RGBA) * 3000 * 3000);
WriteLn(36000000 / (1024 * 1024));
end.

2. The matrix is 3000x3000 of Int32 which is by definition 32 bits (or 4 bytes if you like), hence the name.

My calculations are correct, yours are off as I said.



Thank you for just repeating what I said in my previous post about packed records vs. non-packed. Would you like some assembly with that?
You haven't mentioned the aforementioned bug I see.. That's cool. I'll go away now and hopefully not look back on this post.


Here you go:
http://stackoverflow.com/questions/12781434/why-do-delphi-and-free-pascal-usually-prefer-a-signed-integer-data-type-to-unsig
http://stackoverflow.com/questions/797484/should-i-use-unsigned-integers-for-counting-members

It seems you might need that bounds checking after all.

slacky

2014-08-18 19:05:17

From: Brandon
…

Sure I am wrong, compile this with FPC: http://pastebin.com/KMKGjaaG

From: Brandon
Only thing I messed up was NOT using "packed record"

From: Brandon
72mb rgba bitmap + 144mb integer 2D-matrix + 72mb TPointArray + 72mb TPointList

Aha.. you just managed to get a 3000x3000 integer matrix to be 144MB, and that is correct? Are you 100% sure? :)

Olly

2014-08-18 19:08:02

asdasda LETS BE FRIENDS !!!

Brandon

2014-08-18 19:37:31

From: slacky
Sure I am wrong, compile this with FPC: http://pastebin.com/KMKGjaaG

Aha.. you just managed to get a 3000x3000 integer matrix to be 144MB, and that is correct? Are you 100% sure? :)




Ahh.. I'm just going to have to give up and accept the fact that I just can't teach you or talk to you about unsigned arithmetic and that I can't stay away from reading the replies. I just HOPE you NEVER write a piece of code with unsigned types or machine code. I mean.. if the stackoverflow links and the ideone links said nothing to you, there isn't much more I can really say. FPC IS PROTECTING YOU from the world of unsigned types.


If you need an explanation then here is my VERY LAST attempt.. If you still cannot understand after this then god help you.

In FPC, when you allocate a type smaller than an int, it allocates 1 size larger. So a byte would be a short in memory and MIGHT be promoted to an int (if BUS optimisations are seen fit..). However, you would still be limited to the size of the type you thought you allocated. For this reason, it is ABLE to detect overflows in UNWANTED circumstances and stop it.

Simba doesn't have overflow or underflow guards. This is the exact reason you can access the array's reference count and its const flag and even past that however "undefined" it may seem. You can read or write to memory that isn't yours.. If I had to guess, I'd say you have every type of protection turned on. Again, run that code in ideone which doesn't have such a protection and you'd see that the SAME fpc compiler will allow the byte to overflow.

Lape (working code):

var
P: Array [0..3] of integer;
begin

writeln(P[10]);
writeln(P[-20]);
end.

Now run the same thing in Pascal script? Guess what.. It doesn't work! Now take your for loop and run it in PASCAL SCRIPT.. Is it now safe to assume that PascalScript has more protection from UNDEFINED behaviour? I think so. And now we test for DEFINED behaviour.

Run the same for-loop in pascal script. It will still overflow and wrap around. Is it right to say that BOTH lape and pascal script and C is wrong and that you are correct? What you just cannot understand for god knows why, is that the for to do loop is INCLUSIVE for the 1 billionth time.


var
I: Integer;
begin
For I := 0 To 0 Do
writeln(I);
end.

This code no matter what will ALWAYS print something. It is NOT the same as Do if & while (I < 0). It is the exact same as Do if & while (I <= 0). You're forgetting it increments at the end of the loop. The keyword TO here is very misleading and doesn't mean from meh to blah. It means from meh to blah and including blah. If you read anything I posted previously, you'd have seen this miles away.

If this is unsigned arithmetic, it will ALWAYS overflow because at the end of the loop it will increment the operand.. The operand will wrap around to 0 and again the loop checks the condition and since the condition is perfectly valid, it repeats the same process OVER AND OVER again. More times than I can possibly explain it to you.



And yes you're right a 3000 * 3000 * 4 matrix should not be 144mb (72 * 2) but if you applied any logic to anything I previously said.. you'd realise that I assumed the record: "rgba" was the same size as an integer. I mentioned a "COPY" because I assumed copy on write since you aren't passing it by address but directly. But I guess I really couldn't rely on you to see that far ahead. And for that, I am truly sorry I ever tried to explain a possible problem or anything at all.

Just forget EVERYTHING you saw me post previously and in this post. It's a read only once post. It is for the on-lookers and the hopes I used to have for you that you'd come around. I'm sorry for "cursing back" at you too. Bad on my part. :)

P.S. I wasn't being sarcastic when I said we might really need range guards now. I actually mean that now. And not just for arrays but for overflows too. That'd truly help but also slow down things unnecessarily. I was a little frustrated having to explain this again, but I really really see now why we might need them.:)

nielsie95

2014-08-18 19:58:16

From: slacky
Some bug reports:
Lape has a new bug which I was unable to trace down, and I am not in the mood today to trace it down, just knows it's raised in this piece of code.
- http://pastebin.com/SEzef3TF
I am sorry that I can't narrow it down any further now.


There exists another (old) bug related to for loops, which causes it to go in to an "eternal" loop:

var B:Byte;
begin
for B:=0 to High(Byte) do WriteLn(B);
end;
Note that B is a byte, so when it reaches max-byte (255) it starts over again.



That first bug might be related to the fact that you're importing a function with a constant array parameter. Could you try importing it with constref?

I'm aware of the second bug. There's not really an easy fix, though. For High(Byte) it could be fixed by doing an earlier comparison, but for High(Byte) + 1 there would still be the overflow issue. The best way to fix this would be to add overflow detection, but I'm afraid that would require quite some work.

By the way, today I have added a RangeCheck option for arrays/strings :)

slacky

2014-08-18 22:13:59

From: nielsie95
That first bug might be related to the fact that you're importing a function with a constant array parameter. Could you try importing it with constref?

I'm aware of the second bug. There's not really an easy fix, though. For High(Byte) it could be fixed by doing an earlier comparison, but for High(Byte) + 1 there would still be the overflow issue. The best way to fix this would be to add overflow detection, but I'm afraid that would require quite some work.

By the way, today I have added a RangeCheck option for arrays/strings :)

Awesome work man, that's really great news! :-)

The first bug is related to the changed "const"-definition as you said. I did as you said, changed the export from const to constref, and it worked! :) I should have tested this, as I was aware of the change, whoops.
But thank you very much for the info and help, I appreciate it! :-)

Yeah, I don't mind the actual overflowing once it goes over High(Byte) in this case, I expect that to happen. All I was thinking about was precisely that one could do an earlier comparison. But it's no biggie, i just wanted to mention it in case you had not been made aware of it.

Olly

2014-08-18 22:34:08

From: nielsie95
…


Can i get a explanation on this new constref? :)

slacky

2014-08-18 22:48:33

From: Olly
Can i get a explanation on this new constref? :)

constref is the old const. const has changed behavior, should from what I've gathered now be the same as const in FPC. Maybe Niels can put it in better words :-P

Here is a simple code that shows some of the different behavior:
http://pastebin.com/Kv3pHQf4
Based on this old bug report:
https://code.google.com/p/la-pe/issues/detail?id=22&can=1

Olly

2014-08-18 23:31:56

From: slacky
constref is the old const. const has changed behavior, should from what I've gathered now be the same as const in FPC. Maybe Niels can put it in better words :-P

Here is a simple code that shows some of the different behavior:
http://pastebin.com/Kv3pHQf4
Based on this old bug report:
https://code.google.com/p/la-pe/issues/detail?id=22&can=1


Meh I've only really known const use to be something like 'read only'.. And that's all i've ever used it for.

Curious if this will break SRL-6.

Brandon

2014-08-19 00:24:49

It means you can pass parameters by address (done invisibly by the interpreter/compiler) and guarantee that the person cannot change the pointer but rather only the data it points to..


This is known in Java as pass by reference value (constref in PS) which is what Java programmers call "pass by reference" (var or out keyword in PS). Though its not the same thing. Java programmers just have no idea what they're calling it and have no clue what they're saying. They just copied what it said in the docs.. Java really is pass by reference value (constref) and not pass by reference (var/out).

Anyway..

Example:


//The compiler might as well pass it by value (it's a primitive type).
//However, there's an exception..
//If the value of I changes outside this function,
//the function will see the change. In other words,
//it's an atomic variable and can be modified by
//multiple threads if you so please.
//All threads would see the change/same value.

procedure foo(constref I: Integer);
begin
writeln(I);
end;

//Passed by value.
//Multiple threads can read the value of I.
//Each thread would get its own "copy" of I.
//Changes to the original variable will not affect
//this function's "copy" of it. The function
//will retain the original value of I.
//Usually in threading we call this ThreadLocalStorage (TLS)
//but forget I said that term.
procedure truconst(const I: Integer);
begin
writeln(I);
end;

//TIntegerArray is NOT copied here..
//It is passed by a constant reference.
//This means you can change the values in the array
//but you cannot change the array itself.
//IE: `TI := [10, 5, ...];` is forbidden because the address
//of TI would change.
//however: T[0] := 10; T[1] := 5; T[...] := ...; is not forbidden.
//The address of TI stays the same, but the values in TI changes.
procedure bar(constref TI: TIntegerArray);
begin
TI[0] := 10;
end;


//It is unknown (by me at least) whether this is
//implemented by passing the array by copy/value.
//or if it passes an immutable reference to the underlying
//array (a const pointer to const data).
//The address cannot change. The values cannot change.
//Completely immutable array.
procedure test(const TI: TIntegerArray);
begin
writeln(TI); //you cannot modify TI's data and you cannot assign to TI.
end;


//You can change the data the pointer
//points to but you cannot change the pointer itself.
//IE: `P := @someInt;` is forbidden.

//constref is useless for pointers because
//it is the same as const (unassignable).
//In other words, this is the only
//behaviour which is weird because the pointer isn't
//really "const".. as in: const P const: Integer;
//which would guarantee the pointer's data cannot be changed
//and the pointer cannot be assigned. It can ONLY be read.
//This is not the case however.
procedure meh(const P: ^Integer); //const or constref can be used here.
begin
P^ := 400; //change the value P points to.
//P := nil; //is forbidden as it changes the address P points to (makes it point to something else).
end;


//Pass by reference (not const-reference as in Java)
//In this case, you can change what the pointer points to
//as well as the data it points to.
procedure truevar(var P: ^Integer);
begin
P := @SomeInt; //Change what "P" points to.
P^ := 10; //Change the "value" P holds/points to.
end;



A const ref can be simulated as follows:


type PInt = ^Integer;
type PPInt = ^PInt;

procedure simulate_const_ref(P: PPInt);
begin
P^^ := 100; //Change the value of P.
P^ := nil; //Change the P itsef.
end;

var
I: Integer;
Tmp: ^Integer;
Tmp2: ^Integer;
begin
I := 100;
Tmp := @I;
Tmp2 := Tmp;

writeln('tmp has an address of: ', Tmp);
simulate_const_ref(@Tmp2); //pass the TEMPORARY pointer.
writeln('tmp has an address of: ', Tmp);

writeln('However, tmp2 has an address of: ', Tmp2);
end.

Notice that "tmp" still has the same address. That's because only the address of the copy of "tmp" (aka tmp2) was changed to nil. However, "tmp" itself was never changed. This is how a constant reference works. It simply passes a copy of a pointer to the data. IT does this all behind the scenes and so, you never have to worry about dereferencing the data passed to the function (as shown above). The one difference between the simulated method and the real thing is that the real thing (in pascal only) does not let you assign to it but the simulated one does (even though it has no effect other than letting you re-use a dead variable).


Note that all of the above holds true for records as well. Also note that passing literals will be passed by value or const reference to a const pointer to the data. IE:


some_const_ref_func(100); //will mov 100 into a register and push the register on the stack and call the function.
some_const_ref_func('some str'); //will do the same.

These aren't passed by reference. They also MIGHT not be passed by value. They will simply be stored somewhere and each call to the function will retrieve the address of it (.data section for executables.. dunno for simba scripts) and pass that instead and so changing the data in the function will do nothing or MIGHT be undefined (though I don't think its undefined).

I'm glad you solved it slacky. Did not see that change coming or having such an impact.

Olly

2014-08-19 09:48:05

Interesting!

ps @nielsie95 you should add LineEnding to Lape. :)

nielsie95

2014-08-19 10:30:19

From: slacky
Awesome work man, that's really great news! :-)

The first bug is related to the changed "const"-definition as you said. I did as you said, changed the export from const to constref, and it worked! :) I should have tested this, as I was aware of the change, whoops.
But thank you very much for the info and help, I appreciate it! :-)

Yeah, I don't mind the actual overflowing once it goes over High(Byte) in this case, I expect that to happen. All I was thinking about was precisely that one could do an earlier comparison. But it's no biggie, i just wanted to mention it in case you had not been made aware of it.


Actually, I think this is an issue with libffi. Try returning a LongBool instead of Boolean. const/constref should not have made a difference.

@Olly; As explained above, constref passes arguments by reference (just like var). But unlike var, it does not have to be a variable. Previously, this was the behaviour of const arguments. The new const behaviour actually deviates from Delphi/FPC behaviour in the sense that it should not allow side effects.

slacky

2014-08-19 13:59:30

From: nielsie95
Actually, I think this is an issue with libffi. Try returning a LongBool instead of Boolean. const/constref should not have made a difference.

@Olly; As explained above, constref passes arguments by reference (just like var). But unlike var, it does not have to be a variable. Previously, this was the behaviour of const arguments. The new const behaviour actually deviates from Delphi/FPC behaviour in the sense that it should not allow side effects.

Whoops, it did not help with constref it seems. I am pretty sure it did not recompile the exports in my test for constref (I had in the prev test changed it to pass by value, which works), I retried with constref today, with a full recompile, and it did "Access Violate".

Then I did as you said, changed the function to return a LongBool instead of a Boolean, and that seems to have done the trick, as seen here:
-> http://i.imgur.com/D2bhg60.png

Brandon

2014-08-28 16:35:08

@nielsie95;

I have 3 odd requests and it's probably really difficult to implement (especially the 3rd suggestion) but would be pretty neat.. The third one is pretty useless if the 1st and 2nd existed.



1. TypeOf for Lape..


procedure Foo(var X);
begin
end;


There's currently no way to tell what type "X" is :l

If you cast it to a pointer though.. then you can get the "name" of the variable being passed but you still won't know its type:


procedure Foo(var X);
begin
writeln(Pointer(X));
end;

var
I, B: Integer;
begin
Foo(@I); //Prints "I".. not "Integer"
Foo(@B); //Prints "B".. not "Integer"
end.

Would be quite useful if you could get the underlying type..

That brings up the next request..



2. DeclType:

An enhanced version of "type-of". Basically a "cast" to the underlying type for pointers or an instantiation of some type.


var
I: Integer;
B: decltype(I); //"B" would be whatever type "I" is..
begin
end.

One usage would be:


Procedure foo(var X);
I: decltype(X); //instantiate a "typeof(X)"..
begin
end;

or even:


Procedure Foo: GenType; //return "decltype(SomeType)".
begin
Result := SomeType;
end;

Procedure Bar: Pointer;
begin
Result := @ Something;
end;

begin
writeln(Foo.Field_From_SomeType);

writeln(decltype(Bar)^.Field_From_Something);
end;


I guess you could say that it helps for generic types.



With this in mind, that would allow a 3rd type.. "GenType" would be a pointer to a generic type such that when de-referenced, you get the original value back. This would allow non-casting dynamic polymorphism.. It would be far stronger than TVariant.


type Vehicle = record
Name: String;
Wheels: Integer;
Doors: Integer;
Seats: Integer;
end;

type Car = record(Vehicle)
Automatic: Boolean;
MaxSpeed: Integer;
end;

type Truck = record(Vehicle)
OffRoad: Boolean;
FourWheelDrive: Boolean;
MaxSpeed: Integer;
end;

var
V: Vehicle = ['Vehicle', 4, 2, 4];
C: Car = ['Car', 4, 2, 4, true, 700];
T: Truck = ['Truck', 4, 2, 4, true, true, 400];

Arr: Array of ^Vehicle;
begin
Arr := [@V, @C, @T];
writeln(Arr);
end;

currently prints:


"V"::0x62C0230 ({NAME = Vehicle, WHEELS = 4, DOORS = 2, SEATS = 4})
"C"::0x62C02C0 ({NAME = Car, WHEELS = 4, DOORS = 2, SEATS = 4})
"T"::0x62C0380 ({NAME = Truck, WHEELS = 4, DOORS = 2, SEATS = 4})

Since they are just pointers to "Vehicle", it "slices" and only prints as many fields as Vehicle has..

However, with "GenType" you could do:


var
V: Vehicle = ['Vehicle', 4, 2, 4];
C: Car = ['Car', 4, 2, 4, true, 700];
T: Truck = ['Truck', 4, 2, 4, true, true, 400];

Arr: Array of GenType;
begin
Arr := [@V, @C, @T];
writeln(Arr);
end;

And it'd print:


"V"::0x62C0230 ({NAME = Vehicle, WHEELS = 4, DOORS = 2, SEATS = 4})
"C"::0x62C02C0 ({NAME = Car, WHEELS = 4, DOORS = 2, SEATS = 4, AUTOMATIC = True, MAXSPEED = 700})
"T"::0x62C0380 ({NAME = Truck, WHEELS = 4, DOORS = 2, SEATS = 4, OFFROAD = True, FOURWHEELDRIVE = True, MAXSPEED = 400})

So that every field gets printed.. You'd be able to access each field through a dereference like so:

Arr: Array of GenType;
begin
Arr := [@V, @C, @T];

writeln(Arr[1]^.MaxSpeed); //Access MaxSpeed through pointer to Vehicle..
end;

But the dereference might be unnecessary since you can just cast it to the right type and access the fields.. That's only be possible if you knew what type it was though so the first and second requests would have to exist..



The reason these COULD be useful is for a Generic sort.. For example:


type
RSObject = record
ID: Integer;
X, Y: Integer;
end;


type
WallObj = record(RSObject)
Name: String;
end;

type
GroundObj = record(RSObject)
Name: String;
end;

Function TypeOf(Ptr: Pointer): String;
begin
Result := Between('"', '"::', ToStr(Ptr));
end;

Procedure PtrSwap(A, B: Pointer; Size_Ptr: Integer);
type
BytePtr = ^Byte;
var
I: Integer;
T: Byte;
Begin
T := 0;
While (I < Size_Ptr) Do
Begin
T := BytePtr(A[I])^;
BytePtr(A[I])^ := BytePtr(B[I])^;
BytePtr(B[I])^ := T;
Inc(I);
End;
End;

{*
List: Pointer to an array of objects to be sorted.
Size_Ptr: Sizeof(List[X]);
Comparator: Function to compare two elements in the list given a pointer to each.
*}
Procedure GenSort(List: Pointer; Size_Ptr: Integer; Comparator: Function(A, B: Pointer): Boolean);
type
PUInt32 = ^Uint32;
var
Size: Integer;
I, J: Integer;
Begin
I := 0;
Size := ((PUInt32(List) - sizeof(UInt32))^ + 1) * Size_Ptr;

While(I < Size) Do
Begin
J := 0;
While(J < Size - I - Size_Ptr) Do
Begin
If (Comparator(List[J + Size_Ptr], List[J])) Then
PtrSwap(List[J + Size_Ptr], List[J], Size_Ptr);
J := J + Size_Ptr;
End;
I := I + Size_Ptr;
End;
End;

{*
List: Pointer to an array of pointers to objects to be sorted.
Comparator: Function to compare two elements in the list given a pointer a pointer to each.
*}
Procedure GenSort(List: Array of Pointer; Comparator: Function(A, B: Pointer): Boolean); overload;
var
Size: Integer;
Size_Ptr: Integer;
I, J: Integer;
Begin
I := 0;
Size_Ptr := sizeof(Pointer);
Size := Length(List) * Size_Ptr;

While(I < Size) Do
Begin
J := 0;
While(J < Size - I - Size_Ptr) Do
Begin
If (Comparator(List[J + 1], List[J])) Then
Swap(List[J + 1], List[J]);
J := J + Size_Ptr;
End;
I := I + Size_Ptr;
End;
End;


Function CompRSObjectIDs(A, B: Pointer): Boolean;
begin
writeln('Comparing Variable: "', TypeOf(A), '" With Variable: "', TypeOf(B), '"');
Result := RSObject(A^).ID < RSObject(B^).ID;
end;


var
Arr: Array of ^RSObject;
WO: WallObj;
GO: GroundObj;
Arr2: TIntegerArray;
begin
WO := [5, 50, 50, 'Wall-Picture'];
GO := [1, 100, 100, 'Ground-Ashes'];

Arr2 := [9, 10, 3, 4, 1, 2, 8, 7, 6, 5];

SetLength(Arr, 2);
Arr[0] := @WO; //first object is a WallObj
Arr[1] := @GO; //second object is a GroundObj

GenSort(Arr, @CompRSObjectIDs); //Sort polymorphic array by ID's..

//After sorting, the first object is a "GroundObj" and the second is a "WallObj".. You'd have no idea though unless you check with "TypeOf" above to see which variable name is which..

//GenSort(Arr2, sizeof(Integer), @CompInts);
end;


But after sorting, you have no idea which object is which.. You'd have to store a "name" of each variable to figure out what to cast to in order to get it to print the entire object and not just the parent members..

Dgby714

2014-08-28 23:21:07

From: Brandon
1. TypeOf for Lape..


procedure Foo(var X);
begin
end;


There's currently no way to tell what type "X" is :l


It is *UNTYPED*, it has no type after you pass it to that method. There is no way to get the type of a variable with no type.

Brandon

2014-08-29 03:29:03

From: Dgby714
It is *UNTYPED*, it has no type after you pass it to that method. There is no way to get the type of a variable with no type.


I am aware that it has no "type" information when passed but it has a type before being passed and you can also cast it within the function to the correct type. The point of "Type-Of" is to determine what type was actually passed to the function. Un-typed variables are extremely useless the way they are now.

There is no point to them if you're just going to cast it back to the original type. You might as well just make the parameter strongly typed or an opaque pointer (void*/pointer).

Dgby714

2014-08-29 14:17:05

From: Brandon
I am aware that it has no "type" information when passed but it has a type before being passed and you can also cast it within the function to the correct type. The point of "Type-Of" is to determine what type was actually passed to the function. Un-typed variables are extremely useless the way they are now.

There is no point to them if you're just going to cast it back to the original type. You might as well just make the parameter strongly typed or an opaque pointer (void*/pointer).



You can cast them to any type, and they are useful, they are used in a few of Lape's internal methods.

Brandon

2014-08-29 15:07:50

From: Dgby714
You can cast them to any type, and they are useful, they are used in a few of Lape's internal methods.


:S You can do that with any pointer.. You already knew that but here's an example for the on-lookers I guess..


procedure foo(X: Pointer);
begin
Integer(X^);
String(X^);
TIntegerArray(X^);
//etc.., etc..
end;

procedure bar(X: ^Pointer);
begin
X^ := GetMem(1024);
end;

procedure meh(var X: Pointer);
begin
X := GetMem(1024);
end;

procedure bleh(var X: ^Byte);
var
Ptr: Pointer;
begin
X := Ptr; //implicit cast.
end;


So the untyped variables are useless.. It's just syntax sugar for a reference to some variable type and in the end, you lose all type information and still have to cast it to get that back. All pointers are the same size..

I just don't see the point of having "var" be un-typed.

You can have it strongly typed and still cast it.
You can have a pointer and still cast it.
You can have it as a long (address) and still cast it.

I haven't seen a single script use un-typed variables yet. And even then, it's useless to have it as un-typed because you still have to cast it back to its original type. Again, you might as well make it strongly typed and avoid the cast or have a type-of function so that you can switch case on what type it is..

That's the only way it can be useful.

Dgby714

2014-08-30 00:19:58

From: Brandon
:S You can do that with any pointer.. You already knew that but here's an example for the on-lookers I guess..


procedure foo(X: Pointer);
begin
Integer(X^);
String(X^);
TIntegerArray(X^);
//etc.., etc..
end;

procedure bar(X: ^Pointer);
begin
X^ := GetMem(1024);
end;

procedure meh(var X: Pointer);
begin
X := GetMem(1024);
end;

procedure bleh(var X: ^Byte);
var
Ptr: Pointer;
begin
X := Ptr; //implicit cast.
end;


So the untyped variables are useless.. It's just syntax sugar for a reference to some variable type and in the end, you lose all type information and still have to cast it to get that back. All pointers are the same size..

I just don't see the point of having "var" be un-typed.

You can have it strongly typed and still cast it.
You can have a pointer and still cast it.
You can have it as a long (address) and still cast it.

I haven't seen a single script use un-typed variables yet. And even then, it's useless to have it as un-typed because you still have to cast it back to its original type. Again, you might as well make it strongly typed and avoid the cast or have a type-of function so that you can switch case on what type it is..

That's the only way it can be useful.


It's basicly an void pointer with no need to derefrence.

So yes it is basicly syntax sugar, but it does come in handy in some instances. (i.e. method types)

And those instances are where it is used internally by Lape.

It's not as useful to script writers. Or at least in the sense of what script are usually written for.

nielsie95

2014-09-03 15:45:08

@Brandon; TypeOf might be useful, but it will not work for your described use cases. It will be a compile-time method, so it will not help with untyped parameters. The same goes for decl-type and gentype, as most of this "magic" happens at compile-time. There is little known about the types as runtime.

I understand that this dynamic typing could be very useful, but that is not how Lape was designed. Lape is pretty much a Pascal compiler, which means it is statically typed (type checking happens during compilation). Dynamic types would be awesome, though. For Lape's successor maybe?

rj

2014-09-03 15:47:31

From: nielsie95
@Brandon; TypeOf might be useful, but it will not work for your described use cases. It will be a compile-time method, so it will not help with untyped parameters. The same goes for decl-type and gentype, as most of this "magic" happens at compile-time. There is little known about the types as runtime.

I understand that this dynamic typing could be very useful, but that is not how Lape was designed. Lape is pretty much a Pascal compiler, which means it is statically typed (type checking happens during compilation). Dynamic types would be awesome, though. For Lape's successor maybe?


what about classes

nielsie95

2014-09-03 15:52:08

Class support or dynamic type checking for classes?

Brandon

2014-09-03 16:04:35

From: nielsie95
@Brandon; TypeOf might be useful, but it will not work for your described use cases. It will be a compile-time method, so it will not help with untyped parameters. The same goes for decl-type and gentype, as most of this "magic" happens at compile-time. There is little known about the types as runtime.

I understand that this dynamic typing could be very useful, but that is not how Lape was designed. Lape is pretty much a Pascal compiler, which means it is statically typed (type checking happens during compilation). Dynamic types would be awesome, though. For Lape's successor maybe?



Ahh ={

That sounds like it's bordering on templates (in the sense that it's compile time checking) rather than generics..

Even if it was compile time, I could think of one use case:


procedure foo(var X);
begin
if (typeof(X) = typeof(Integer)) then //that would have to generate a compile time boolean..
begin
end;
end;

In that case, the if statement would be equivalent to:


if (true) then

if (false) then

And would still allow better type casting in the end. You'd be able to determine what type to cast to at the very least.


I haven't found a work-around of the lack of typeof yet.. Dgby found a work-around for the lack of "offsetof" last year:


//OffsetOf - PtrUInt(@(Struct(nil + 1)^.Y)) - 1;

type meh = record
A, B, G, R: byte;
end;

type mp = ^meh;

begin
writeln((PtrUInt(@(mp(nil + 1)^.A)) - 1)); //0 bytes from the beginning..
writeln((PtrUInt(@(mp(nil + 1)^.R)) - 1)); //offset of 6 bytes from the beginning..
end.

and that was extremely useful when going through the fields of a structure by pointer. I could see typeof and offsetof having some usage. Offsetof being more useful.


I can't see dynamic typing getting into Lape though. It is a nice and useful idea but too much work for runtime typing.

nielsie95

2014-09-03 16:13:44

It's neither templates nor generics, really. As @Dgby714; described, it's mostly just syntactical sugar for void pointers. Every now and then useful for some compiler trickery and Delphi/FPC compliance, but overall pretty useless.

Brandon

2014-10-14 21:49:27

@nielsie95; What's the difference between SetLength and SetArrayLength (or Length and GetLength) and why do we have both.. they do the same thing and are the same speed :S

Tried looking it up but it isn't anywhere..


procedure testOne;
var
Arr: Array of Integer;
I, T: LongWord;
begin
T := getSystemTime();
For I := 0 To 100000 do
SetArrayLength(Arr, I);
writeln('Time: ', (getSystemTime - T));
end;

procedure testTwo;
var
Arr: Array of Integer;
I, T: LongWord;
begin
T := getSystemTime();
For I := 0 To 100000 do
SetLength(Arr, I);
writeln('Time: ', (getSystemTime - T));
end;


begin
testOne;
testTwo;
end.

Olly

2014-10-14 21:53:52

From: Brandon
@nielsie95; What's the difference between SetLength and SetArrayLength (or Length and GetLength) and why do we have both.. they do the same thing and are the same speed :S

Tried looking it up but it isn't anywhere..


procedure testOne;
var
Arr: Array of Integer;
I, T: LongWord;
begin
T := getSystemTime();
For I := 0 To 100000 do
SetArrayLength(Arr, I);
writeln('Time: ', (getSystemTime - T));
end;

procedure testTwo;
var
Arr: Array of Integer;
I, T: LongWord;
begin
T := getSystemTime();
For I := 0 To 100000 do
SetLength(Arr, I);
writeln('Time: ', (getSystemTime - T));
end;


begin
testOne;
testTwo;
end.


It's a wrapper to make it pascalscript compatible https://github.com/SRL/Lape/blob/cd8a7f99d9508161814074089fb4ec90e0bbb1b3/lputils.pas#L46

Gu3st...

2014-10-14 22:02:27

From: Brandon
@nielsie95; What's the difference between SetLength and SetArrayLength (or Length and GetLength) and why do we have both.. they do the same thing and are the same speed :S

Tried looking it up but it isn't anywhere..
IIRC, there is (was?) a bug with GetArrayLength and SetArrayLength with lape

E: http://bugs.villavu.com/view.php?id=283

slacky

2014-10-14 22:06:53

From: Brandon
@nielsie95; What's the difference between SetLength and SetArrayLength (or Length and GetLength) and why do we have both.. they do the same thing and are the same speed :S

As you might have guessed, SetArrayLength and SetLength is the same function (literally), SetArrayLength is simply an alias. Same goes for GetArrayLength which is an alias for Length.

I believe it's in lape so that programs written for PascalScript should be a bit simpler to have compatible with (or port to) Lape.
> Lape/lputils.pas#33

Edit: meh.. olly was faster then me

Brandon

2014-10-14 22:12:10

From: slacky
As you might have guessed, SetArrayLength and SetLength is the same function (literally), SetArrayLength is simply an alias. Same goes for GetArrayLength which is an alias for Length.

I believe it's in lape so that programs written for PascalScript should be a bit simpler to have compatible with (or port to) Lape.
> Lape/lputils.pas#33



I guessed that but.. https://github.com/RRLibrary/RRL/commit/adc2724155fa0d78f64f9c886f36e717782a2ee5

seems to suggest that there is a "Speed" increase.. the name of the commit is "Speed Modifications".. that's why I was confused.

slacky

2014-10-14 22:32:09

From: Brandon
I guessed that but.. https://github.com/RRLibrary/RRL/commit/adc2724155fa0d78f64f9c886f36e717782a2ee5

seems to suggest that there is a "Speed" increase.. the name of the commit is "Speed Modifications".. that's why I was confused.

This is just some speculation:
Considering that RRL was written for PascalScript, and PascalScripts own SetLength is somewhat slow -> will be noted whenever you try to allocate a few megabytes (or more)..
Then, say if SetArrayLength WAS [it's not the case now at least] calling Free Pascals SetLength you would achieve a notable speedup.

tls

2014-10-14 22:36:20

From: slacky
This is just some speculation:
Considering that RRL was written for PascalScript, and PascalScripts own SetLength is somewhat slow -> will be noted whenever you try to allocate a few megabytes (or more)..
Then, say if SetArrayLength WAS [it's not the case now at least] calling Free Pascals SetLength you would achieve a notable speedup.


This.

Gu3st...

2015-04-16 17:37:00

Windows API calls, how do I use them with Lape?

slacky

2015-04-16 19:09:18

From: Zyt3x
Windows API calls, how do I use them with Lape?

You don't. You will need to export the windows functions you need using a plugin

Gu3st...

2015-05-06 21:18:25

How does "set" work in lape?
Can someone explain what's going on in this code?
var
t : 0..127;
loweralpha : set of 'a'..'z';
//alphanumeric : ['A'..'Z', 'a'..'z', '0'..'9'];

begin
t := 127;
writeLn(t); // 127
t += 1;
writeLn(t); // 128?

writeLn('a' in loweralpha); // False
writeLn('a' in ['A'..'Z', 'a'..'z', '0'..'9']); // True
end;

I'd also like to see line 4 be valid

slacky

2015-05-06 22:20:57

From: Zyt3x
How does "set" work in lape?
…

I think this piece of code can explain it better then what I can do with words, well at least without putting too much time in to it:

type
TAnsiSet = set of #0..#127; //a set - can store all chars in the give range.
TSubRange = 0..127; //subrange (not a set)

var
i: TSubRange;
chars: TAnsiSet;
begin
i := -10; //should error (or overflow), but requires overflowcheck (which isn't added yet).
i := 0; //legal
i := 99; //legal
i := 199; //should error (or overflow)...

WriteLn('There are no chars here:', chars);//not initalized yet...

chars := ['0'..'9', 'A'..'F', 'a'..'f']; //chars is a subset within the bounds of the TAnsiSet-type
WriteLn(chars); //[0..9,a..f,A..F]
WriteLn('5' in chars);


chars := ['a'..'e']; //..
WriteLn(chars); //[a,b,c,d,e]
WriteLn('a' in chars);//simple and efficient lookup.
end;
The code in the comment at line 4 isn't valid because it's not a range, so it can't be converted to a set-type.

Gu3st...

2015-05-07 09:18:44

From: slacky
I think this piece of code can explain it better then what I can do with words, well at least without putting too much time in to it:
-snip-
The code in the comment at line 4 isn't valid because it's not a range, so it can't be converted to a set-type.
Thanks, helps a lot :)