SRL Archive - Senior Scripts and Snippets

Lape


nielsie95

2011-02-28 10:17:41

Ohai!

Lape is an interpreter written in FPC/Delphi with a Pascal-like syntax (mostly compatible with Pascal Script). It is built with speed and compatibility in mind. I work on this now and then, but I post this here because it has reached a stage of which I'm proud :)

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)

You wont find any comments in the code yet, but I hope this will change in the future :hypocrite: The goal is to be able to run Pascal Script scripts with only minor modifications. Currently not compatible is that Pascal Script supports Try-Finally-Except (in that order – Lape does support Try-Except-Finally / Try-Except / Try-Finally) and in Pascal Script you can assign to constant parameters (while you can't in Lape).


To do:
  • Variant, Enum, Set, Method types
  • (imported) classes
  • IS, AS, IN operators
  • Exit, Continue, Break, raise
  • with(, switch?) struct
  • Labels?
  • Compiler defines, include files
  • Callbacks (platform specific!!)
  • Compiler functions: SetLength, Length, Low, High, Inc, Dec, Succ, Pred, Ord, SizeOf
  • In script function overloading/overriding/forwarding
  • Constant arrays/records
  • Short circuit boolean evaluation
  • Add types/methods/variables with help of strings in the back end
  • Load/save compiled code

Marked in orange are the points which are needed to be Pascal Script compliant. Missing anything?


Syntax examples:

function Test(const a: Int32; b: Int32 = 20; c: Int32 = 30): Int32;
const
v1: Int32 = (Random(100, 200) div 10) * 10; //Gets evaluated at compile time, so this will be the same every call
v2: Int32 := (Random(100, 200) div 10) * 10; //Gets evaluated at runtime
begin
WriteLn('v1: ' + IntToStr(v1));
WriteLn('v2: ' + IntToStr(v2));
{a := a + b;} //This wont work, because a is a constant parameter

Result := a + b + c + v1 + v2;
end;

begin
WriteLn('First begin end');
//If the begin-end doesn't end with a dot, it gets evaluated (at runtime)
end;

var
i: Int32 = 100;
begin
WriteLn(Test(3,,7)); //Empty parameter to take default param

//No need for an assignment and has support for else clause
for i to 0 do
WriteLn(i)
else
WriteLn('No loop, i > 0');

//Support for step keyword
//For loops get converted to while loops, so ints/extended/chars/pointers/etc. are all supported
for i := 1 to 10 step 3 do
a := i * 3;

//while supports else clauses, too
while (a > 0) do
a := a - 3
else
Writeln('a was <= 0');

//Assignments are operators
if ((a := i := 2) > 1) then
WriteLn('Nice :) ' + IntToStr(a) + ' ' + IntToStr(i));

WriteLn(Test(i)); //Take default for the other 2 params
end;


Please test and point out any bugs. I've added a compiled executable for those who don't have FPC or don't want to compile. It's still very much in progress, so the form is what I use for development/testing. To run the script: press Go2 :) I'm open for suggestions, so let's hear them!

Nielsie95

Wizzup?

2011-02-28 10:39:17

Epic win! I really hope this project goes well. :)

Hoping to integrate it into Simba in the near future!

Hooray for Linux support and faster execution and local functions and not assigning to constant parameters and nielsie95! <3

E: And pointers!

EvilChicken!

2011-02-28 10:49:10

Oh, damn.
This looks awesome beyond words, I can't wait to have this replace Simba's current interpreter!

Niels, you need to make more tutorials for stuff so other people can learn some of the cool stuff you know.

nielsie95

2011-02-28 11:04:53

All in time :p
It will probably take a long time before this can be considered a decent PS replacement. Last week I had time to work on this because I had holidays, but that time is over. :p After the above features are added, everything still needs thorough testing/debugging. And because the code isn't properly documented, it may be very hard for an outsider to work on it. I'm always willing to clear things up for anyone who needs help with it, though.

Gu3st...

2011-02-28 12:57:46

From: EvilChicken!
Oh, damn.
This looks awesome beyond words, I can't wait to have this replace Simba's current interpreter!

Niels, you need to make more tutorials for stuff so other people can learn some of the cool stuff you know.
Bolded words pretty much summed it up! :p
Awesome, Niels! You keep on amazing me :)

Could you tell me what this line does:
* if ((a := i := 2) > 1) then

nielsie95

2011-02-28 13:21:21

Assignments can be used in expressions in Lape. So a := i will "return" a, which in turn you can use for another expression.

a := i := 2; is the same as i := 2; a := i; and ((a := i := 2) > 1); is the same as i := 2; a := i; a > 1;

Gu3st...

2011-02-28 13:55:03

From: nielsie95
Assignments can be used in expressions in Lape. So a := i will "return" a, which in turn you can use for another expression.

a := i := 2; is the same as i := 2; a := i; and ((a := i := 2) > 1); is the same as i := 2; a := i; a > 1;
Nifty :)

lordsaturn

2011-02-28 15:14:47

Looking forward to seeing this on github… ^^

Naum

2011-02-28 16:30:54

Beautiful work as ever niels..

nielsie95

2011-03-04 10:25:34

Not much progress, but here's the repository: http://code.google.com/p/la-pe/

Wizzup?

2011-03-04 11:46:30

LGPL, yay.

Dan Cardin

2011-03-04 16:21:16

b: Int32 = 20;
lovely! This totally seems to rLape the other PS alternatives

nielsie95

2011-03-11 19:26:26

Worked on enums/subranges and sets and all the hassle that comes with them (open array initialization, which meant constant arrays). I think they work pretty well now. Array initialization through brackets should work too for static arrays (also for constants). :)


type
enum = (hoi, hai, bye = 5, bai);
var
xx: array[enum] of Int32 = [1..7];
aa: enum = hai;
bb: set of enum;
begin
WriteLn(xx[bai]);
xx := [7, 6, 5, 4, 3, 2, 1];
bb := [aa..bai] - [hai];
if (bye in bb) then
WriteLn('nice');

//for loop without variable
for 1 to 3 do
WriteLn('test');
end;

Attachments aren't updated, so you'd have to compile yourself :p

lordsaturn

2011-03-18 22:03:16

How is this coming?

Wizzup?

2011-03-19 05:56:46

He's actively working on it; it's coming around really nicely. :)
http://code.google.com/p/la-pe/source/list

nielsie95

2011-03-19 06:20:06

Yup, I'm doing more than I expected. :p
Compiler magic functions (like SizeOf, Ord, Inc, etc) will probably be done next, along with the Exit, Continue, Break and Halt keywords. I'd say it would be pretty usable after these additions.

Since my last post, I also added shortstrings (String[20]) and worked on making adding imported resources easier (things like functions/types/vars can now be added through string headers in the back end).

A thing I still have to figure out how I'm going to do it is SetLength, as it requires the typeinfo at runtime. Another problem is the method type. Currently, there are 2 sorts of methods in Lape: script methods and imported methods. These are not called the same way. Pascal script solves this by only allowing script methods to be used as variable, but it would be nice to be able to use imported methods too.

Here's what I mean:

var
a: procedure(s: String);
begin
//This works in Pascal Script only if MyStringProc is a script method
a := @MyStringProc;
//But this would be nice too, right?
a := @WriteLn;

a('ohai');

Would it be worth it to also allow the second option?

Dan Cardin

2011-03-19 09:52:18

that looks really cool, but until i cant think of anything i would use it for off the top of my head.

Nava2

2011-03-19 12:02:17

From: nielsie95
*snip*

Another problem is the method type. Currently, there are 2 sorts of methods in Lape: script methods and imported methods. These are not called the same way. Pascal script solves this by only allowing script methods to be used as variable, but it would be nice to be able to use imported methods too.

Here's what I mean:

var
a: procedure(s: String);
begin
//This works in Pascal Script only if MyStringProc is a script method
a := @MyStringProc;
//But this would be nice too, right?
a := @WriteLn;

a('ohai');

Would it be worth it to also allow the second option?


Yes, I think so. As far as a scripter is concerned, it shouldn't matter where the method comes from, it should just be a method.

What if you abstract the `Method` type to allow for both (could also allow for plugins if thats different). Then when you need to use any method internally it will have the necessary function pointers towards the needed ones. I mean, if you can wrap the current methods so that you can share the same function, this will work.

Sorry if its confusing, I'm thinking along the lines of the way that the MML sets up its TClients (linux, windows, mac, etc).

I'm really happy that this is getting active development. It looks great. :)

nielsie95

2011-03-19 15:26:19

If I understand you correctly, you're talking about overriding? I'm afraid that wont work as they are called differently (parameter wise) and when they are variables they could be either for the compiler. I think I'll probably solve it with a simple if-check and maybe make some special keywords for the scripter to explicitly define them external/internal.

Today I implemented the magic compiler functions: Length, Low, High, Inc, Dec, Succ, Pred, Ord and SizeOf. Still need SetLength, New, Dispose and maybe Copy. Still thinking about how to implement them. Variants are easy to add and I also think Exit,Break,Continue and Halt are relatively easy to do.

Wizzup?

2011-03-19 17:07:09

Hiep Hiep Hoera!

(Back to cramming I go)

Nava2

2011-03-20 01:25:38

From: nielsie95
If I understand you correctly, you're talking about overriding? I'm afraid that wont work as they are called differently (parameter wise) and when they are variables they could be either for the compiler. I think I'll probably solve it with a simple if-check and maybe make some special keywords for the scripter to explicitly define them external/internal.

Today I implemented the magic compiler functions: Length, Low, High, Inc, Dec, Succ, Pred, Ord and SizeOf. Still need SetLength, New, Dispose and maybe Copy. Still thinking about how to implement them. Variants are easy to add and I also think Exit,Break,Continue and Halt are relatively easy to do.


No no, I'm talking about abstraction of the Object used for calling methods. Then you create a method at runtime which will implement the necessary methods. If that is held true then the type of method is not necessary.

Its polymorphism.

nielsie95

2011-03-20 10:24:46

Yeah, that's what I was talking about too :p Remember that it's compiled to bytecode. It would indeed work if you'd just "ran" the syntax tree (that's what DWS does, btw).

lordsaturn

2011-03-22 03:00:04

Load/save compiled code
win. Is it possible to compile the code then run it (all inside simba) without saving it to an executable? If so, it would be a major improvement over interpretation from a speed standpoint.

nielsie95

2011-03-22 04:31:25

Yes, that's possible, but for now it only compiles to bytecode. I think the speed's already pretty decent, though :)

nielsie95

2011-03-25 15:59:40

I've finished Exit,Break and Continue today and reuploaded a compiled version (attached to the first post), Go2 runs the script.

About the speed, just try it for yourself :)
The default script in the test program runs in about 1.4s on my computer, while the PS variant runs in about 33s with Simba. Of course you can't entirely compare those numbers as Simba isn't compiled with O3 (best optimization), while my test program is. PS also has a way to pause/stop scripts while they're running, so it probably has an extra check in the program loop which consumes time too.

Gu3st...

2011-03-25 20:48:16

From: nielsie95
PS also has a way to pause/stop scripts while they're running, so it probably has an extra check in the program loop which consumes time too.
But would it increase the time it takes by 2300%? :p

nielsie95

2011-03-26 15:04:28

Don't think so ;) I hope it will run in around 2s max..

On another note, Dgby is currently working on a Simba fork with Lape support :)

Gu3st...

2011-03-26 20:21:45

From: nielsie95
Don't think so ;) I hope it will run in around 2s max..

On another note, Dgby is currently working on a Simba fork with Lape support :)
Thank you niels.. I'll have to change my pants now :(


:D

nielsie95

2011-03-29 06:19:15

:D

Did some more work. Added variants and made byte/word/longbools work. Also added a compiler define to allow syntax like:


WriteLn('hai');

begin
var xx := 0;
WriteLn('xx = ' + IntToStr(xx));

for var counter: Int32 := 0 to 10 do
WriteLn('hoi');
end;

Not sure if I like it, though..

Nava2

2011-03-29 11:11:03

From: nielsie95
:D

Did some more work. Added variants and made byte/word/longbools work. Also added a compiler define to allow syntax like:


WriteLn('hai');

begin
var xx := 0;
WriteLn('xx = ' + IntToStr(xx));

for var counter: Int32 := 0 to 10 do
WriteLn('hoi');
end;

Not sure if I like it, though..


I am OK with the loop declaration, but not with the `in code` declaration. I know its kinda a bit hypocritical, but its not pascal syntax. That's just C syntax with English statements.

Wizzup?

2011-03-29 11:20:43

Looks like it's nearing pascalscript compliance. :D

nielsie95

2011-03-29 11:23:48

From: Nava2
I am OK with the loop declaration, but not with the `in code` declaration. I know its kinda a bit hypocritical, but its not pascal syntax. That's just C syntax with English statements.


Yeah, it's not very Pascal'ish, but it can improve readability in some cases? Variable blocks are still supported, too. What do you think about expressions outside blocks (the writeln outside the begin-end)?

Nava2

2011-03-29 11:40:30

From: nielsie95
Yeah, it's not very Pascal'ish, but it can improve readability in some cases? Variable blocks are still supported, too. What do you think about expressions outside blocks (the writeln outside the begin-end)?


That's very python-esque. I like the idea, but I guess the point is why? It seems like bad style to me.

OH OH OH! IDEA!

From python.. when you have a library, you can still have `main` methods by invoking
if __name__ == "__main__":
I think this would be a *really* nice feature to have and allow us to test things in files rather than having all sorts of testing files all over the place.

Perhaps using a `Main` name would be equivalent as well (similar to Java's approach).

A nice thing about this would be the inclusion of the include during runtime idea.

Smartzkid

2011-03-29 22:54:50

Is it possible to make the do and this then statements optional?

nielsie95

2011-03-30 04:32:41

I think you mean then? That's one's possible, yes. Do is possible in a while loop, but with a for loop it's not so easy. Besides, don't you think that's a bit too much?

@Nava: including during runtime will probably not happen. Accessing the include would be pretty hard too, when functions and variables are statically linked. Let's just start with a normal way to include files :p

Smartzkid

2011-03-31 04:45:15

From: nielsie95
I think you mean then? That's one's possible, yes. Do is possible in a while loop, but with a for loop it's not so easy. Besides, don't you think that's a bit too much?


Languages that impose wordiness upon programmers annoy me to no end. For example, C#:

for(int i = 0; i < r; i++)
{
DoSomething;
}

I'm sure you know this would be a lot longer in PascalScript. Additionally, variables scoped within the body of a loop are very convenient.

Wizzup?

2011-03-31 04:56:57

Pascal is verbose; it works with words. It would be silly to mix words with C-alike syntax.

Smartzkid

2011-03-31 05:58:58

If removing a piece of syntax from a language will not harm the expressivity of the language, the syntax should be removed.

Additionally, who wants to type begin when they can type {?

Wizzup?

2011-03-31 08:41:51

I suppose everyone who codes pascal. Lape is not C, so I don't see why you'd want to use character used for comments as begin and end open blocks.

Smartzkid

2011-03-31 10:01:09

Yes, same as everyone who codes VB typing DIM and shit. And who likes VB?

We're already using PascalScript - an unofficial, unstandardized language - why not change the language so it's easier to code?

nielsie95

2011-03-31 11:45:37

I don't want to differ too much from Pascal (Script) syntax. If we had the option to start all over again, I'm sure we would have chosen a different interpreter/compiler. Now it's just not worth the effort to change languages, in my opinion. A thread about it: http://villavu.com/forum/showthread.php?t=63510.

Worked on compiler directives. Implemented $I, $Include, $Include_Once, $Define, $IfDef, $IfNDef, $Else, $EndIf. Not entirely satisfied, though. Because the parser works with a lookahead system, most parts are processed twice. In the following situation:

{$IFDEF lala}
begin
end.
I would've liked to show an error message, but because of the lookahead, the compiler thinks there's nothing there. I'll probably change that behaviour somewhere later on.

Smartzkid

2011-03-31 15:06:15

I understand that huge changes aren't plausible at this point, but it would be really, really awesome if the compiler could ignore missing do and then statements.

Wizzup?

2011-03-31 17:54:02

Seriously…? I'd also prefer to have `than' and `then' for the illiterate programmers.

HyperSecret

2011-04-01 10:44:04

Do you have git or something set up for commits to the most recent versions of this anywhere? or is the only source we have at our hands the one in the zip files on the first post?

nielsie95

2011-04-01 10:47:50

In this thread you'll find a link to the repository and a link to a Simba fork with Lape. Still hardly any comments, but feel free to ask questions :)

Added something I personally would've found useful at times in Pascal Script: function overriding.


procedure WriteLn(s: string); override;
begin
inherited('OVERRIDE: ' + s);
end;

procedure test;
begin
WriteLn('hoi1');
end;

procedure test; override;
begin
WriteLn('hoi2');
inherited();
end;

procedure test; override;
begin
WriteLn('hoi3');
inherited();
end;

begin
test();
end;

outputs:

OVERRIDE: hoi3
OVERRIDE: hoi2
OVERRIDE: hoi1

I also changed parsing here and there so there is a lot less lookahead, which should speed up parsing and fix the "bug" I was talking about earlier. Next up: method types?

Wizzup?

2011-04-02 12:16:35

A very nice feature indeed… You can easily hook into functions or write your own Mouse function. I assume it's also possible to override functions added by Simba?

Gu3st...

2011-04-02 12:22:52

YES! I'd very much like override functions in Simba!! Would also make the pointer system I wrote for MSI and the pointer system in SRL pointless (no pun intended)

Would make hooking so much easier.

lordsaturn

2011-04-02 12:43:42

From: Zyt3x
YES! I'd very much like override functions in Simba!! Would also make the pointer system I wrote for MSI and the pointer system in SRL pointless (no pun intended)

Would make hooking so much easier.


Nice code ya got there.

Sir R. M8gic1an

2011-04-02 16:45:27

This looks like an extremely good and useful peace of work man :) props

~RM

Gu3st...

2011-04-02 18:32:25

From: lordsaturn
Nice code ya got there.
Thanks! The one in the public MSI is outdated and doesn't really work that good, but I have an updated version on my HDD which I haven't committed to my MSI fork yet. But back on-topic now! :)

nielsie95

2011-04-07 06:01:21

@Wizzup: As you can see in my example, that is indeed possible :)

I got record initialization and method types done. I chose not to use the Delphi/FPC way with "field: value", as this was easier to implement.

var
p: TPoint = [2, 1];
p2: TPoint = [,1]; //Don't initialize the first field

proc: procedure; //This can either be an imported method or a method defined in the script, the compiler will decide how to invoke
procI: external procedure; //This is an imported method
procS: private procedure; //This is a method defined in the script
begin
p := [a,b];
proc := Test; //No @
end;

Also note that you cannot just assign overloaded methods to such a var, you'll have to create a wrapper for that. Maybe I'll implement something like WriteLn._1 or WriteLn[1] to access the overloaded methods. You don't use the "@" to get the address of a function, which is also incompatible with Pascal Script. Not sure if I'm going to change that (I'll probably have to if I make () optional to invoke a method).

With statements are a bit harder than I thought (they aren't that hard, but I'd rather do them properly to easily add features like OOP and namespaces later). My plan:

  • With statements
  • Labels
  • Compiler magic functions ToString, Write, WriteLn, New, Dispose, SetLength
  • Comments
After this, I'd like to take it slow and just fix bugs (as they come up, not planning on hardcore testing myself). After that we'll see, but don't expect too much. As school's coming up again, the take it slow part might come even sooner :p

By the way, it looks like the example in the first post doesn't work any more, because it expects a constant for v1 (and the Random function isn't a constant). I don't think I'm going to revert that behaviour.

Still open to suggestions, comments, criticism :)

Wizzup?

2011-04-07 14:56:42

Just wondering, why not use the @ to get the address? It makes a lot more sense IMO. And as far as I know it, FPC does it this way too. The other way it is ambiguous: will it call the function and then return the result or will it pass the reference to the function?

nielsie95

2011-04-07 17:29:03

It only makes sense when you can invoke methods without the parentheses. FPC doesn't entirely do it that way. When you have variables of method types, you can just do a := b. In Lape, script functions are constants of method types, so there's no need for @ to get the address.

Wizzup?

2011-04-07 17:33:27

IIRC I suggested to only make it call methods when you add () :p
I think '@' just makes it a whole lot clearer.. I guess it's just personal preference.

nielsie95

2011-05-19 11:04:01

It makes no sense to use the address operator when there's no need for it (what else would "functionname" without "()" and "@" mean in an expression?). It's either optional parentheses and need for the address operator or needed parenthesis and no need for the address operator.

Anyway, I've added the with statement and short circuit boolean evaluation. I've also realised that classes aren't a top priority as they can be "imitated" using pointers and records. I'd say that it's (feature-wise) very usable after setLength is implemented.

Gu3st...

2011-05-19 12:22:35

To me, @ is meaning I have to read it as a pointer, and makes it easier for me to keep track of what's what in my code

nielsie95

2011-05-19 13:04:30


function funcA: Integer;
begin
end;

var
fA, fB: function: Integer;
begin
fA := funcA;
fA := fB;
end;

How would it be clearer if it would say fA := @funcA? The fA := fB wouldn't change. I guess it's just a personal matter, but I'm not going to make methods an exception in the implementation just because some people find it easier to read. In Pascal Script/FPC you need to have address operator to make sure the function doesn't get called (because you can call functions without the parentheses). In Delphi you don't need "@" either.

nielsie95

2011-06-18 10:42:34

Almost done with ToString. I made it an overloaded method which adds methods on the fly as it needs them. The methods can be overridden in script. The only type to be done is methods, but that's something for later.


function ToString(i: Int32): string; override;
begin
Result := 'hoi! -> ' + inherited(i);
end;

var
x: set of (hai, bai, kai);
begin
x := [hai, kai];
WriteLn(ToString(bai)); //enum
WriteLn(ToString(x)); //set
WriteLn(ToString(@x)); //pointer
WriteLn(ToString([1, 2, 3])); //array
WriteLn(ToString(TPoint([2, 3]))); //record
end;

{outputs:
bai
[hai, kai]
0x4962000 ([hai, kai])
[hoi! -> 1, hoi! -> 2, hoi! -> 3]
[X: hoi! -> 2, Y: hoi! -> 3]
}

I want to make Write and WriteLn magic methods which take a variable number of parameters and then converts to string using ToString, so you can do things like:


WriteLn('Hello ', name, '! It''s over ', 9000);
WriteLn(TPoint([1, 2]), ' -- ', TPoint([3, 4]));

I've also made overloaded functions accessible through an index: ToString[0] and when assigning to a variable it will try to resolve the wanted function automatically: var x: function(p: TPoint): string = ToString. I've also did a similar thing for pointers. When dereferencing an untyped pointer, it will automatically try to find the correct type:


var
p: Pointer;
x: Int32;
y: Int8;
begin
x := 1;
p := @x;
x := p^; //Similar to PInt32(p)^
y := p^; //Similar to PInt8(p)^
end;

Drakan

2011-06-18 10:47:20

This is looking great nielsie, im getting pretty excited about this! Seems like it's gonna be sick :) Thanks for all your hard work!

nielsie95

2011-06-18 15:25:21

Thanks, I appreciate it! :)
100 commits now! Added Write and WriteLn as explained above.

Gu3st...

2011-06-18 19:56:54

Glad you're still working on this! Great job, nielsie :)

nielsie95

2011-07-03 11:35:02

Added typeless parameters and did some overall fixing. While working on SetLength, I've found a bug:


procedure test(s: string);
begin
s[2] := 'w';
end;
begin
WriteLn(s); //'abc'
test(s);
WriteLn(s); //'awc' (expected: 'abc')
end;

It has to do with how strings work. They are actually dynamic arrays, but they (should) have copy-on-write, which means the string shouldn't get copied until s[2]:='w'. I didn't implement that yet (and still haven't, as it requires quite some work).

As strings are basically dynamic arrays, I could also implement the copy-on-write mechanism for dynamic arrays. What do you think? (Note: the code above would be expected behavior if the type was "array of Char" instead of string – or shouldn't it be? ;)).

Dgby714

2011-07-05 10:26:43

From: nielsie95
typeless parameters


=) How does this work? script-wize? or Is it only for functions that are imported?

nielsie95

2011-07-05 10:37:19

http://docwiki.embarcadero.com/RADStudio/en/Parameters_%28Delphi%29#Untyped_Parameters

It basically means that there is no type checking :p

Dan Cardin

2011-07-05 15:50:44

a la python? if so, its actually quite useful and generally, if it poses any problems at all, the problems just reveal incorrect coding rather than allowing for flaws.

Nava2

2011-07-05 20:57:11

This looks excellent Nielsie! Out of curiosity any idea on speed comparison to PS and is it still cross-platform?

Gu3st...

2011-07-05 21:06:22

From: Nava2
This looks excellent Nielsie! Out of curiosity any idea on speed comparison to PS and is it still cross-platform?
First page:
Support for multiple platforms (only tested with Windows x86 and Linux x64 for now, but supports virtually every platform FPC supports).
Fast(er) execution (it's a lot faster than Pascal Script)

Drakan

2011-07-05 23:30:13

Yay I'm excited, hurry up ;p monk. But seriously I'm really looking forward to this and the speed increases and the overriding and the typeless params and the awesomeness and your good looks and everything…..0

Nava2

2011-07-06 00:43:30

From: Zyt3x
First page:


I'm aware, I was wondering if it was maintained! :)

Dgby714

2011-07-06 14:32:27

niels, will you be adding operator overloading (in the script)?

Ex -

program _;

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

operator +(a, b: TPoint): TPoint; overload;
begin
Result.x := a.x + a.y;
Result.y := a.y + b.y;
end;

var
pointa, pointb: TPoint;

begin
pointa := Point(5, 2);
pointb := Point(1, 2);

WriteLn(pointa + pointb); //(6, 4)
end.

nielsie95

2011-07-07 07:49:54

From: Dan Cardin
a la python? if so, its actually quite useful and generally, if it poses any problems at all, the problems just reveal incorrect coding rather than allowing for flaws.

No, not a la python, unfortunately. Variants is the best you can get for now. =\

From: Nava2
This looks excellent Nielsie! Out of curiosity any idea on speed comparison to PS and is it still cross-platform?

I think it should still be cross platform, as I don't use any platform specific code like inline assembly or Windows API calls. I'm sure about the speed, though: still a lot faster than Pascal Script ;)

From: Dgby714
niels, will you be adding operator overloading (in the script)?

Ex -

program _;

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

operator +(a, b: TPoint): TPoint; overload;
begin
Result.x := a.x + a.y;
Result.y := a.y + b.y;
end;

var
pointa, pointb: TPoint;

begin
pointa := Point(5, 2);
pointb := Point(1, 2);

WriteLn(pointa + pointb); //(6, 4)
end.

Yes, at some point probably :p For imported types, this is already possible.

Coh3n

2011-07-07 07:53:11

From: nielsie95
Yes, at some point probably :p For imported types, this is already possible.
Where would something like that be useful?

Dgby714

2011-07-07 10:42:04

From: Coh3n
Where would something like that be useful?


Well, Simba already did it for TPoint in PS. Otherwise every time you want to compare two points you would have to do it like this.

if ((Pa.x = Pb.x) and (Pa.y = Pb.y)) then


Currently PS and Lape can only do it for imported types. So any custom types made by a scripter cant use operators (+, -, =)

nielsie95

2011-07-07 11:22:37

PS can't do it out of the box; I "hacked" it in. With Lape, you can specify behavior for every operator :)

@cohen: might be useful for things like complex numbers.

Dgby714

2011-07-07 11:24:34

From: nielsie95
PS can't do it out of the box; I "hacked" it in.


LOL, I didn't know. Did you read my pm?

Coh3n

2011-07-08 03:51:27

Oh right on, that's pretty cool. Everything looks pretty awesome so far. :) Question though, why'd you call it Lape?

Dgby714

2011-07-08 10:22:55

From: Coh3n
Question though, why'd you call it Lape?


I would also like to know!

nielsie95

2011-07-09 16:23:37

Lazarus pascal engine :p
Not the best name, but not the worst either.

Coh3n

2011-07-10 18:31:47

Oh nice, not a bad name at all. :)

Dan Cardin

2011-07-10 23:18:48

because it Lape's the competition!

not a la python? not type checking?

Dgby714

2011-07-11 02:12:56

=) Niels, your patch to the RUTIS wrappers didn't work or was incomplete. Tho if were dropping PS (are we?) should it really just be wrapping PS's?

From: Dan Cardin
because it Lape's the competition!

not a la python? not type checking?


You lost me….

Dgby714

2011-07-11 03:38:29

Prob my fault, but I get this? Anything you can tell me, "!delayed"?

Exception in Script: Runtime error: "Access violation" at line 1, column 65 in file "!delayed"

Bobarkinator

2011-07-11 08:59:57

You haven't perchance tried it out on OS X have you? I realize I'm probably in the severe minority using it…

nielsie95

2011-07-11 10:29:12

From: Dan Cardin
because it Lape's the competition!

not a la python? not type checking?

If a variable doesn't have a type, the compiler doesn't know how to compile expressions, so you'll always need to cast it to a type before you can use it.

From: Dgby714
Prob my fault, but I get this? Anything you can tell me, "!delayed"?

Exception in Script: Runtime error: "Access violation" at line 1, column 65 in file "!delayed"

What script are you trying to run? The delayed part probably means it's a compiler function.

From: Bobarkinator
You haven't perchance tried it out on OS X have you? I realize I'm probably in the severe minority using it…

I only have (easy) access to a Windows 7 machine, but you are free to test and report bugs :)

Bobarkinator

2011-07-11 14:50:06

Compiles and runs! I'd be perfectly happy building this into Simba and not having to worry about pascal script haha ;)

nielsie95

2011-07-20 08:49:08

Cool! Is that the repository or the zip in the first post?

Drags asked me about classes functionality (a la Titan) and I think it's best to answer here. Yes, classes would be nice, but don't count on support too soon. They are somewhere at the bottom of my to-do list (and you've seen how fast I finish those lists.. :p). First I'd like to get some other things done so a basic release can be prepared (not talking about Simba). Then it'll be mostly bugfixing at first.

Simba could've had support for classes for a long time now, with DWS or FPC. I believe I even strongly hinted on trying to port DWS again ;)

Dgby714

2011-07-20 09:30:12

From: nielsie95
Cool! Is that the repository or the zip in the first post?

Drags asked me about classes functionality (a la Titan) and I think it's best to answer here. Yes, classes would be nice, but don't count on support too soon. They are somewhere at the bottom of my to-do list (and you've seen how fast I finish those lists.. :p). First I'd like to get some other things done so a basic release can be prepared (not talking about Simba). Then it'll be mostly bugfixing at first.

Simba could've had support for classes for a long time now, with DWS or FPC. I believe I even strongly hinted on trying to port DWS again ;)


I told him >..> He was asking in IRC about classes =P

I'd like them, but I'd like a Lape with SetLength more =) (or imported classes =S)

Drakan

2011-07-20 09:55:30

Yah i pm'ed that question before getting on irc dgby :P

Thanks for the update! Would rather see this get out and working first before the class support etc. Thanks for your hard work! I'll start testing once I get back from vacation on the 30th.

Bobarkinator

2011-07-21 00:31:49

I'm pretty sure it was the repository Nielsie

Wizzup?

2011-07-23 16:17:26

Looks like it's nearly ``SRL'' ready; full SetLength support seems like the main thing lacking. We don't really use ``as'' and ``is'', and classes/callbacks are mainly for forms anyway. :)

nielsie95

2011-07-29 19:05:20

Today I've fixed a rather large bug that was hidden pretty deeply (took me all day to figure out what was wrong) :) SetLength is coming along pretty well too. The only thing that doesn't work yet is copying reference counted variables when changing lengths (needed for arrays of strings and arrays of arrays, for example). This means that TPointArrays should already behave properly. Finishing SetLength shouldn't take very long.

I've already been running some bigger scripts. For example, Ben's CPascal testing script to solve a maze works and my own mazesolver works too (it was a script for a scripting contest hoster by mixster) :)

My mind is full of ideas for extensions (operator overloading, custom initialization/finalization for each type, function inlining, type extensions, namespaces, etc..), but I have to restrain myself to keep working on the basics first. Even though some of those features are (relatively) easy to add, I have to draw the line somewhere. I'm going to keep myself to the earlier posted list, so that means:

  • Finish SetLength, New, Dispose
  • Fix up some behavior (literals vs constants and function invocation without parenthesis maybe)
  • Write some comments (and perhaps documentation)
  • Fix bugs (ongoing)

This means no new features for a while (probably :p), but it also means that Lape can be tested and hopefully can be get to a somewhat stable state. I'm not planning on doing a lot of hardcore testing myself, but I was hoping to get help with this (many hands make light work). Another thing I was hoping to get help on is a language guide. I think that it's a good idea to have a guide on the language and its features (rather than relying on tutorials on the forums). I know a lot of you have written tutorials on SCAR/Simba and it would be nice if we could create one big tutorial. I bet we could come a long way just by copy pasting (but more on this later) :)

Wizzup?

2011-07-30 05:10:30

I suppose you don't like me saying this :p , but I wouldn't mind writing some of that language guide. I was planning to write some ``All-in language/scripting'' guide anyway (or at least partially write stuff my self and partially copy paste, assembling stuff from other tutorials).

nielsie95

2011-08-01 14:08:27

Finished SetLength, New and Dispose :)
I made it so that New and Dispose not only support pointer types, but also regular types. This might get useful if I introduce custom type initialization (custom finalization is already supported as can be seen below). SetLength supports setting the length of multidimensional arrays too:


procedure _Dispose(var p: TPoint); overload; //TPoint does normally not have to be finalized, so overload the function
begin
WriteLn('Disposing point ', p);
p := [-1, -1];
end;

procedure _Dispose(var p: array of TPoint); override; //TPointArray does have to be finalized, so override the old function
begin
WriteLn('Disposing TPA!');
inherited();
end;

procedure test;
var
x: array of array of TPoint;
begin
SetLength(x, 2, 2);
x[0, 0] := [123, 456];
end;

var
z: ^TPoint;
begin
New(z);
z^ := [78, 90];
WriteLn('z: ', z);
Dispose(z);

test();
end;

(*OUTPUT:

z: 0x32D9E8 ({X = 78, Y = 90})
Disposing point {X = 78, Y = 90}
Disposing TPA!
Disposing point {X = 123, Y = 456}
Disposing point {X = 0, Y = 0}
Disposing TPA!
Disposing point {X = 0, Y = 0}
Disposing point {X = 0, Y = 0}
*)

Wizzup, of course I appreciate you want to contribute to the project! It's just that you make a lot of promises and not all of them are kept that quickly (it takes you quite some time usually :p). Is anyone else interested in helping writing a language guide? I know Coh3n, Nava, Bebe, NCDS and Naum (and probably more) have written some impressive tutorials on Pascal Script. Could I interest any of you in writing/copying some parts for the language guide? :)

Drakan

2011-08-01 14:15:43

Nice nielsie! Getting one step closer! :)

Nava2

2011-08-01 15:29:58

OMG THAT ARRAY REFERNCE IS SEXY.

  x[0, 0] := [123, 456];

Also, give me some direction and I can make it work. :)

Wizzup?

2011-08-01 15:44:20

From: Nava2
OMG THAT ARRAY REFERNCE IS SEXY.

  x[0, 0] := [123, 456];

Also, give me some direction and I can make it work. :)


What do you mean make it work?

Nava2

2011-08-02 12:53:27

From: Wizzup?
What do you mean make it work?


In regards to the documentation, I had a feeling that was an ambiguous statement. Sorry!

nielsie95

2011-08-04 14:04:36

Thanks Nava, that's great! :) I'll write a thread on it somewhere in the future..

Today I've added support for dynamic array initialization from open arrays and from static arrays. I've also added support for the plus operator for dynamic arrays:


var
x: array of TPoint;
begin
x := [[1, 2], [3, 4]];
x := x + x[0];
WriteLn(x);
end;

I've also fixed up the wrapper generator for Simba, which means that quite a number of functions are now exported to Lape in the "lape-integration" branch (MoveMouse, FindColor, etc). :) After (most of) the other functions are imported, I think it should be possible to run basic scripts in Simba. Compared to Pascal Script, Lape is currently just missing labels and classes I think?

Nava2

2011-08-04 14:40:53

What about including?

nielsie95

2011-08-04 14:49:52

These compiler directives are currently supported:

  • ifdef, ifndef, else, endif
  • define, undef
  • i, include, include_once
These should be familiar. :p
  • 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}. So yes, includes are possible :)

Nava2

2011-08-04 14:56:34

… In other words, scripts *could* be converted to Lape and used?

E: Simple ones, w/o imported classes.

nielsie95

2011-08-04 15:01:34

In theory, yes. I assume there are still a lot of bugs, though. Converting shouldn't really be an issue (unless you use labels or classes). Currently, Lape is a bit stricter on the use of semicolons and constant parameters. The biggest difference is that functions need parentheses to be invoked, but I think I might change that to follow Delphi/FPC/PS syntax.

Dgby714

2011-08-04 15:01:34

The lape-integration branch gives me this now.. =( Wanted to check out the new features.
Failed to initialise the interpreter: Forwarded declaration doesn't match at line 1, column 48 in file "!import"

Coh3n

2011-08-04 15:08:49

nielsie, what kind of form support does Lape have, if any?

Dgby714

2011-08-04 15:22:40

From: Coh3n
nielsie, what kind of form support does Lape have, if any?


None, TForm is an imported class.

Eventually we will get at least imported classes but don't count on it soon.

Coh3n

2011-08-04 15:43:00

From: Dgby714
None, TForm is an imported class.

Eventually we will get at least imported classes but don't count on it soon.
Okay. More and more people are starting to use forms so it may be something to think about.

Drakan

2011-08-04 16:08:59

From: nielsie95
The biggest difference is that functions need parentheses to be invoked, but I think I might change that to follow Delphi/FPC/PS syntax.


I vote on this. Would love to see that :) I think using parentheses is kinda annoying when not needed.

nielsie95

2011-08-04 17:15:44

Dgby, I accidentally left a bug in before, it should work now :)

Cohen, forms as you use them in Pascal Script will not work yet (as they're imported classes). However, it can easily be made to work with some extra work. Instead of importing the class, you could just import the functions to work with the class.


Form := TForm.Create(nil);
Form.Width := 200;
Form.ShowModal();

//could become

Form := TForm_Create(nil);
TForm_SetWidth(Form, 200);
TForm_ShowModal(Form);

It's not very convenient, but it should work. I don't think it's a good idea to do this for Simba, though.

Wizzup?

2011-08-04 17:37:01

Personally, I'd really love to see parenthesis forced to invoke a function. Otherwise it's not clear whether it is a variable or a function. I've always found this extremely annoying in Free Pascal. (I probably don't always do it either - probably because the compiler doesn't bug me about it; but I think it makes code more readable.)

Coh3n

2011-08-04 19:44:09

From: nielsie95
Dgby, I accidentally left a bug in before, it should work now :)

Cohen, forms as you use them in Pascal Script will not work yet (as they're imported classes). However, it can easily be made to work with some extra work. Instead of importing the class, you could just import the functions to work with the class.


Form := TForm.Create(nil);
Form.Width := 200;
Form.ShowModal();

//could become

Form := TForm_Create(nil);
TForm_SetWidth(Form, 200);
TForm_ShowModal(Form);

It's not very convenient, but it should work. I don't think it's a good idea to do this for Simba, though.
Ehh doesn't seem worth it right now if you plan on adding imported class later anyway.

From: Wizzup?
Personally, I'd really love to see parenthesis forced to invoke a function. Otherwise it's not clear whether it is a variable or a function. I've always found this extremely annoying in Free Pascal. (I probably don't always do it either - probably because the compiler doesn't bug me about it; but I think it makes code more readable.)

I strongly second this.

NCDS

2011-08-04 23:17:41

From: Coh3n

From: Wizzup?
Personally, I'd really love to see parenthesis forced to invoke a function. Otherwise it's not clear whether it is a variable or a function. I've always found this extremely annoying in Free Pascal. (I probably don't always do it either - probably because the compiler doesn't bug me about it; but I think it makes code more readable.)


I strongly second this.


When you first started doing this it drove me crazy, but I've began to do it more and more myself without even noticing. :p


As for the mini "debate" on this; It's really the same as trying to decide who has "better" standards. It's simply personal preference. However, I'm not opposed to having it as I do think it increases readability.

Nava2

2011-08-05 00:34:20

From: Coh3n
I strongly second this.


I strongly support this as well.

But, perhaps use a define for the option? Why not have more flexibility, aye?

Coh3n

2011-08-05 01:24:49

From: Nava2
I strongly support this as well.

But, perhaps use a define for the option? Why not have more flexibility, aye?
Pointless, IMO. Just have one or the other. I'd vote for a forced standard if it was possible.

Wizzup?

2011-08-05 05:42:03

Well, I can imagine Nielsie would at least like a compiler define for it, the question is: do we want to enable it for Simba. :)

Bobarkinator

2011-08-05 14:49:24

Nielsie, do you program in Python ever? You seem to be making many of these features very Python-esque…

Dgby714

2011-08-05 15:05:21

From: Bobarkinator
Nielsie, do you program in Python ever? You seem to be making many of these features very Python-esque…


I just see a lot of Pascal…. PS was just weird…

nielsie95

2011-08-05 15:05:58

I've added the invocation without parenthesis today. It's an option ($AutoInvoke+ or $F+), which is enabled by default. I decided to do it like this because I do not want to differ from Pascal Script too much.

Bobarkinator, I haven't made a Python program more difficult than Hello World. What features remind you of Python? Other than the array/record initialization, it is all pretty much Pascal :)

Bobarkinator

2011-08-06 01:21:48

Yeah, the arrays definitely remind me of Python. And then the optional parameters thing (I don't remember if you're doing this, and I know it was already in PS) made me think of Python. I guess mostly that little sample you posted earlier just reminded me of how I would write a Python program, just with Pascal syntax.

Freddy1990

2011-08-06 09:24:44

Looking good Niels, I'm going to enjoy working with this!

nielsie95

2011-08-12 08:27:09

I updated the first post with a new executable (the source zip isn't updated - for the latest source you can use Google code). I've also added some regular functions like IntToStr, StrToInt, GetTickCount, Random, etc. The lape-integration Simba branch can also run basic scripts, so feel free to try out some things! If you did (not) get something to work, please let me know! :)

Lape still compiles on Windows (x86, x64), Linux (x86, x64) and Delphi 2010. 64 bit execution seems a bit slower. I'm not sure what's the cause of this (perhaps the compiler is less optimized for x64?). Delphi XE2 will get support for x64 (and OS X) too, so it will be a nice comparison ;)

EDIT: It also (sort of) works on an ARM Windows Mobile 4 pocket pc (about 10 years old). Unaligned memory access is not supported, but the base script works :) I believe newer versions of the ARM architecture (the ones you find in today's smartphones) do support unaligned memory access.

nielsie95

2011-08-15 12:25:49

Today I added stack length initialization to help fix a bug that would happen with excessive stack usage (e.g. with heavy recursion). The test script that brought this bug to my attention was the Ackermann algorithm script from the RUTIS v2 engine (it looks like it has support for classes now).

(The function below gets executed 11164370 times!)

//Taken from the RUTIS project ([url]http://www.delphipraxis.net/160542-rutis-engine-v2.html[/url])
//Adjusted to compile with Lape
program Ackermann;

var
Count: Int64 = 0;

function ackerman(n, m: cardinal): cardinal;
begin
if n = 0 then
result := m + 1
else
if m = 0 then
result := ackerman(n - 1, 1)
else
result := ackerman(n - 1, ackerman(n, m - 1));
Inc(Count);
end;

var
tt : Cardinal;
begin
tt := GetTickCount;
writeln('ackerman(3, 9) = ' + IntToStr(ackerman(3, 9)));
tt := GetTickCount - tt;
writeln('Duration = ' + IntToStr(tt));
writeln('Count = ' + IntToStr(Count));
end.

I couldn't resist comparing to other engines :p I added the count at the end on purpose to make sure the compilers didn't optimize using tail recursion.

FPC: ~100ms
Lape: ~2000ms
paxCompiler: ~7400ms (using SCAR Titan)
RUTIS: ~17600ms (compiled to .exe)
PS: Didn't finish (using Simba)
DWS: Didn't finish

These results are (of course) specific to this test and do not give a general overview. This is primarily a recursion test, but I'm still a bit proud of the results :)

From the looks of it (in general), Lape is a tad faster than DWS, a fair bit faster than RUTIS and a whole lot faster than PS (I usually don't compare to paxCompiler). I'm not so sure why paxCompiler is so "slow" in this test, as it should compile to machine code.

Feel free to test and search for bugs! =D

Wizzup?

2011-09-06 07:20:30

I'm not sure where your thread about the documentation for lape was. So I'll just post here. Has anyone started yet? I'll be done with my thesis on the 20th September and then I'll hopefully have quite some free time and I look forward to writing documentation for lape.

Nava2

2011-09-06 16:33:45

Just waiting for direction, sir!

Wizzup?

2011-09-21 19:50:55

So I've done a little work. It's not much and probably not worth a lot either (I'm not such a good writer yet), but I've started. I don't really have any directions other than… just writing. I do intend to continue working on this though, hopefully with some help!

You can temporarily(!) find it on my experimental(!) blog: http://blog.wizzup.org/blog/lape

.rst file so far, in case anyone wants to work on it. (We'll need this in the git repo later, I'm also planning to split it up in multiple files and it'll be using sphinx which has more features than my blog, but this was easier for now.)

..
:Author: Merlijn Wajer
:Date: 2011-09-21
:Title: Lape Documentation
:Categories: lape

Welcome to Lape's tutorial!
===========================

Contents:

.. contents::

Introduction to Lape
====================

..
Intro is ruk

Lape is an interpreter for a subset of the Pascal language.

.. NOTE::
I really don't know what to write here yet.

The Basics
==========

Introduction to Programming
----------------------------

Lape features a language very similar to the programming language `Pascal
<http://freepascal.org>`_. Writing a programming language is called
*programming*:

*The purpose of programming is to create a program that exhibits a certain
desired behavior.*

To learn programming you have to - as with all things - start with the very
basics. Let us start a very basic but important question: What is a **Program?**
Simply put, a program is a set of logical statements and instructions.
A logical statement is as the name implies - logical. An instruction is simply
an operation the computer will execute - the results of the instruction can vary
- you can make the computer add two numbers, have it draw a line on the screen,
download a file and much more.

Say we have the follow sentence in English:

*If it is raining I will have to put on my raincoat.*

This roughly translates into the following **code**:

.. code-block:: pascal

if (it_is_raining) then
put_on_raincoat();

Now, if you're new to programming, this probably looks very weird. There are
lots of programming language and they all look different - this particular
language is called **Pascal**.

Basically, the line below is a logical construct:

.. code-block:: pascal

if (it_is_raining)

Whereas the following line is an instruction, in this case an instruction
that tells us to perform other instructions define in the **procedure**
*put_on_raincoat*.

.. code-block:: pascal

put_on_raincoat()

When combining other logical statements (there are a lot more statements than
just **if**) with instructions, it is possible to construct a **program**.


Hello, Lape!
------------

Now we've gone through a little background, let's start by writing our first
Pascal program.

Observe the following program:

.. code-block:: pascal

begin
writeln('hi');
end.

Immediately we see something new - **begin** and **end**. Every program needs a
**begin** and **end**, it defines where the program *starts* and where it
*stops* - that is when the last instruction has been reached.
Lape will execute instructions as directed by the logical statements until the
end of the program is reached.

So what does the line below really do?

.. code-block:: pascal

writeln('hi');

To find out, we have to **run** or **execute** the program.

.. NOTE::
TODO: COVER HOW TO EXECUTE A PROGRAM. (IN SIMBA??)

After *running* the *program*, you should see something like this:

Compiled successfully in 70 ms.
hi
Successfully executed.

So, the function *writeln* prints something out.
Try changing **'hi'** to something else, if you do it properly, it should print
something else. If it fails after you've changed something - don't worry, just
keep on reading.


Procedures
----------

Now you're thinking, what is a procedure? If we look at the example in
`Hello, Lape!`_, *writeln* is a **procedure**.

A **procedure** can be seen as a small program on its own, containing
instructions and logical statements. When a *procedure* is **invoked**,
the program executes the instructions and logical statements *in* the
procedure, which also has a **begin** and **end**. Once the procedure
*ends*, the program continues as usual.


*procedures* are particularly useful if you do want to write a lot of
stuff at the same time.

A simple example:

.. code-block:: pascal

procedure I_am_a_procedure;
begin
writeln('Hello from the procedure');
end;

begin
writeln('Hello from the program');
I_am_a_procedure();
writeln('And we are back in the program');
end.



If and Else
-----------


Functions
---------





Loops in Lape
=============

Arrays in Lape
==============

Pointers in Lape
================

Classes in Lape
===============

Coh3n

2011-09-21 20:12:32

Looks nice so far, Wizzup. :)

Wizzup?

2011-09-25 14:54:12

Did some more work (see previous post for link). I doubt it is very accessible to the absolute noob, but I guess it will be done more justice once we get to the reference part.

E: Did some reference work too.

nielsie95

2011-09-25 17:27:43

I really appreciate it! I couldn't find a documentation tool to my liking, so I kind of postponed the documenting part. But this is looking great!

I did, however, do some work on the engine itself. Methods of objects can now be declared and invoked and every type can hold subdeclarations. This means that every type can hold methods (and perhaps variables). Example:


var i: Integer = 1;
begin
WriteLn(i.Inc().Abs().ToStr());
end;

The backend is there, but it's not yet made easy to import these kinds of things. I also still need a way to handle class functions (like constructors). Also, there's now a magic namespace named "system" through which you can access all global declarations (like System.Break, System.WriteLn, or System.Random).

Nava2

2011-09-25 23:20:08

From: nielsie95
I really appreciate it! I couldn't find a documentation tool to my liking, so I kind of postponed the documenting part. But this is looking great!

I did, however, do some work on the engine itself. Methods of objects can now be declared and invoked and every type can hold subdeclarations. This means that every type can hold methods (and perhaps variables). Example:


var i: Integer = 1;
begin
WriteLn(i.Inc().Abs().ToStr());
end;

The backend is there, but it's not yet made easy to import these kinds of things. I also still need a way to handle class functions (like constructors). Also, there's now a magic namespace named "system" through which you can access all global declarations (like System.Break, System.WriteLn, or System.Random).


This is starting to look like OOP! :)

Gu3st...

2011-09-26 10:14:03

From: Nava2
This is starting to look like OOP! :)
Yeah, woah this is looking really nice :D

Wizzup?

2011-09-26 15:18:18

Well, I'm done with it for a few days, need to work on some other stuff.

Here's the source if anyone feels like adding more: (perhaps we can put it in the lape repo later?)

..
:Author: SRL
:Date: 2011-09-21
:Title: Lape Documentation
:Categories: lape

Welcome to Lape's tutorial!
===========================

.. contents::

Introduction to Lape
====================

Lape is an interpreter for a subset of the Pascal language.
This guide contains a compact introduction to programming and more specifically
programming with Lape. It is by no means a complete guide on learning how to
program. There are awesome books and more comprehensive articles on becoming a
programmer.

This guide serves as reference and compact introduction to lape.

The Basics
==========

Introduction to Programming
----------------------------

Lape features a language very similar to the programming language `Pascal
<http://freepascal.org>`_. Writing a programming language is called
*programming*:

*The purpose of programming is to create a program that exhibits a certain
desired behavior.*

To learn programming you have to - as with all things - start with the very
basics. Let us start a very basic but important question: What is a **Program?**
Simply put, a program is a set of logical statements and instructions.
A logical statement is as the name implies - logical. An instruction is simply
an operation the computer will execute - the results of the instruction can vary
- you can make the computer add two numbers, have it draw a line on the screen,
download a file and much more.

Say we have the follow sentence in English:

*If it is raining I will have to put on my raincoat.*

This roughly translates into the following **code**:

.. code-block:: pascal

if (it_is_raining) then
put_on_raincoat();

Now, if you're new to programming, this probably looks very weird. There are
lots of programming language and they all look different - this particular
language is called **Pascal**.

Basically, the line below is a logical construct:

.. code-block:: pascal

if (it_is_raining)

Whereas the following line is an instruction, in this case an instruction
that tells us to perform other instructions define in the **procedure**
*put_on_raincoat*.

.. code-block:: pascal

put_on_raincoat()

When combining other logical statements (there are a lot more statements than
just **if**) with instructions, it is possible to construct a **program**.


Hello, Lape!
------------

Now we've gone through a little background, let's start by writing our first
Pascal program.

Observe the following program:

.. code-block:: pascal

begin
writeln('hi');
end.

Immediately we see something new - **begin** and **end**. Every program needs a
**begin** and **end**, it defines where the program *starts* and where it
*stops* - that is when the last instruction has been reached.
Lape will execute instructions as directed by the logical statements until the
end of the program is reached.

So what does the line below really do?

.. code-block:: pascal

writeln('hi');

To find out, we have to **run** or **execute** the program.

.. NOTE::
TODO: COVER HOW TO EXECUTE A PROGRAM. (IN SIMBA??)

After *running* the *program*, you should see something like this:

.. code-block:: txt

Compiled successfully in 70 ms.
hi
Successfully executed.

So, the function *writeln* prints something out.
Try changing **'hi'** to something else, if you do it properly, it should print
something else. If it fails after you've changed something - don't worry, just
keep on reading.


Procedures
----------

Now you're thinking, what is a procedure? If we look at the example in
`Hello, Lape!`_, *writeln* is a **procedure**.

A **procedure** can be seen as a small program on its own, containing
instructions and logical statements. When a *procedure* is **invoked**,
the program executes the instructions and logical statements *in* the
procedure, which also has a **begin** and **end**. Once the procedure
*ends*, the program continues as usual.

A simple example:

.. code-block:: pascal

procedure I_am_a_procedure;
begin
writeln('Hello from the procedure');
end;

begin
writeln('Hello from the program');
I_am_a_procedure();
writeln('And we are back in the program');
end.

Here, *I_am_a_procedure* is a procedure, identified by having the word
**procedure** in front of it. Then follows a usual *begin*, followed by some
instructions and terminated with an *end*.

Running this program writes the following:

.. code-block:: txt

Compiled succesfully in 71 ms.
Hello from the program
Hello from the procedure
And we are back in the program
Successfully executed.

As you can see, Lape first executes:

.. code-block:: pascal

writeln('Hello from the program');

And then *invokes* or *calls* the procedure *I_am_a_procedure*, which on its
turn tells Lape to execute the following:

.. code-block:: pascal

writeln('Hello from the procedure');

And finally, Lape executes:

.. code-block:: pascal

writeln('And we are back in the program');

As you can see, the *execution* of a program is perfectly logical and follows
very strict steps. A procedure can be used to *divide* code into smaller pieces,
to prevent writing the same instructions and logical constructs over and over.

Now that we have a general idea on how Lape executes your code, we'll move onto
*variables*.

Variables and Types
--------------------

What is a variable? Let us consult Wikipedia [*]_

In computer programming, a variable is a symbolic name given to some known
or unknown quantity or information, for the purpose of allowing the name to
be used independently of the information it represents. A variable name in
computer source code is usually associated with a data storage location and
thus also its contents, and these may change during the course of program
execution.

.. [*]
[url]https://secure.wikimedia.org/wikipedia/en/wiki/Variable_(computer_science[/url])

In layman terms: We use **variables** in programming to store values for reuse
of the value. There are different types of values: *Variables* are always of a
specific **type**.

Consider the following code:

.. code-block:: pascal

var
sum: integer;
begin
sum := 0;
writeln(sum);
sum := sum + 42;
writeln(sum);
sum := sum + 43;
writeln(sum);
end.


Here, **sum** is a *variable*. The **type** of *sum* is **Integer** and
**var** indicates that we are about to **declare** one or more variables.

First of all, a *variable* of *type* *Integer* can store whole numbers.
Both positive and negative. There is a limit on the maximum (and minimum)
value of the number, but that is not relevant yet.

So, let us start with:

.. code-block:: pascal

sum := 0;

This instructions makes the value of *sum* equal *0*, zero.

.. code-block:: pascal

sum := sum + 42;
sum := sum + 43;

These two statement successively add 42 and 43 to the value of *sum*, by setting
the value of *sum* to the value of *sum* plus a number.

*Output* of the program is as follows:

.. code-block:: txt

Compiled succesfully in 71 ms.
0
42
85
Successfully executed.


Comments
--------

*Code* can include **comments**, comments are used to comment on the code,
typically to make it easier for the reader to understand the code.
Comments on a single line start with *//* and comment that span multiple lines
start with *{* and end with *}*. See the following example:

.. code-block:: pascal

begin
writeln('Hello, there'); // This line prints 'Hello, there'

{
This is a comment; the writeln that follows in the comments will be
not executed and treated as comment instead.
writeln('Hello, I am in a comment');
}
writeln('This is no longer a comment');
end.

If and Else
-----------

So far we've covered how your program is run, what a procedure is, how you can
make simple use of variables and how to comment your code to make it more
readable. Note that we've previously spoken of logical statements, but have not
yet thoroughly discussed them.

The *if* statement consists of a **condition** and one of more
**instructions** that follow the condition:

.. code-block:: pascal

if condition then
instruction;

Obviously *condition* must be either **True** or **False**, there is no *maybe*.
Apart from the **Integer** type introduced in `Variables and Types`_, Lape also
supports a **Bollean** type - which can in contrast to an *Integer*, only hold
two kind of values: *True* and *False*.

Thus, the following code is perfectly valid:

.. code-block:: pascal

var
a_condition: Boolean;
begin
a_condition := True;
if a_condition then
writeln('a_condition was true!');
if a_condition = false then
writeln('a condition was false!');
end;

And it will write:

.. code-block:: txt

a_condition was true!


Lape will try evaluate your *condition* to either True or False.
If it cannot do this, your code is invalid. As a result, you can combine logical
constructs if then evaluate to either *True* or *False*. See `Not, And, Or,
Xor`_ on combining logical constructs.

For example, the following code is **invalid**:

.. code-block:: pascal

if 42 then
writeln('The answer to life, the universe and everything!');


The **if** statement can optionally make use of an **else** clause,
simplifying our previous code:

.. code-block:: pascal

var
a_condition: Boolean;
begin
a_condition := True;
if a_condition then
writeln('a_condition was true!') // Note that there is no semicolon here now
else
writeln('a condition was false!');
end;

If you wish to perform more than one operation in you *if* statement, use the
**begin** and **end** keywords:

.. code-block:: pascal

var
a_condition: Boolean

begin
a_condition := True;
if a_condition then
begin
writeln('a_condition is true');
writeln('this is another procedure call');
end
else
begin
writeln('a_condition is false');
writeln('This line and the line above will however never be printed');
end;


Not, And, Or, Xor
-----------------

Lape contains a few special *logical operators*: **Not**, **And**, **Or** and
**Xor**.

Not
~~~

The **Not** instruction negates the value that follows it:

.. code-block:: pascal

var a_boolean: boolean;

begin
a_boolean := not False;
if a_boolean then
writeln('a_boolean is True');
end;


A simple **Truth Table** for the **not** operator:

========= =====
not True False
not False True
========= =====

And
~~~

The **And** operator takes two logical values (or constructs that *evaluate*
to a value) and *evaluates* to *True* if both these values are *True*, otherwise
it evaluates to *False*.

Truth table for the **and** operator (treat A and B as logical
values/constructs):

===== ===== =======
Inputs Output
------------ -------
A B A and B
===== ===== =======
False False False
True False False
False True False
True True True
===== ===== =======


Or
~~

The **Or** operator takes two logical values (or constructs that *evaluate*
to a value) and *evaluates* to *True* if any of these values are *True*,
otherwise it evaluates to *False*.

Truth table for the **or** operator (treat A and B as logical
values/constructs):

===== ===== ======
Inputs Output
------------ ------
A B A or B
===== ===== ======
False False False
True False True
False True True
True True True
===== ===== ======


Xor
~~~

===== ===== =======
Inputs Output
------------ -------
A B A xor B
===== ===== =======
False False False
True False True
False True True
True True False
===== ===== =======


Variables cont.
---------------

The section `Variables and Types`_ gave a very basic introduction on variables,
just enough to get you to this section. First, we'll introduce a few more basic
**types**:

.. code-block:: pascal

var
b: boolean;
s: string;
i: integer;

begin
b := True or False; // b = True
s := 'Hello, ' + 'World'; // Hello, World
i := 24 * 2;
end;

We've introduced one new *type*:

- A **string** consists of one or more characters, denoted by the
surrounding **'**.

As a short reminder:

- A **boolean** can either hold the value *True* or *False*.
- An **integer** holds a number.

Now, looking at the previous code, we notice the **or** operator being applied
to *True* and *False*, but this is nothing new.

Moving on, we can see that the *string* **s** is being given the value
*'Hello, ' + 'World'*. What does an addition of two *strings* even mean?
In this case, the two strings *'Hello, '* and *'World'* are *combined* to
*'Hello, World'*. The **+** operator is not defined for every type: it mainly
works on strings and integers.

The last statement takes the number *24* and **multiplies** it by *2*.


Logical evaluation and parentheses
----------------------------------


Functions
---------


Records in Lape
---------------

Loops in Lape
-------------

Arrays in Lape
--------------

Pointers in Lape
----------------

Classes in Lape
---------------

Lape Reference
==============

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

Operators
---------


Assignment Operator
~~~~~~~~~~~~~~~~~~~

- :=

.. code-block:: pascal

var
b: boolean;
a: integer;
s: string;
sa: array of string;

begin
b := True;
a := 41+1;
s := 'This parrot is an ex-parrot';
setlength(sa, 4);

// Pick the odd one out
sa[0] := 'This parrot is no more';
sa[1] := 'It is pleading demise';
sa[2] := 'If you had not nailed him to the perch he would be pushing up the daisies!';
sa[3] := 'My hovercraft is full of eels';
end;

The assignment operator assigns a *value* to a *variable*.

Equality Operators
~~~~~~~~~~~~~~~~~~

Equality
::::::::

The **=** operator checks for equality of two basic types of the same type:

.. code-block:: pascal

if (42 = 42) and ('God is God' = ('God is' + ' God') ) then
writeln('Everything equals itself, surprisingly');

Inequality
::::::::::

The **<>** operator is similar to the **=** operator, but checks for inequality
rather than equality:

.. code-block:: pascal

if '42' <> 'The answer to life, the universe and everything' then
writeln('Blasphemy!');

Greater than
::::::::::::

The **>** operator returns true if the first value is greater than the second
value:

.. code-block:: pascal

if 43 > 42 then
writeln('42 is larger than 43');

Greater than or equals
:::::::::::::::::::::::

The **>=** operator returns true if the first value is greater than *or equal
to* the second value:

.. code-block:: pascal

if (43 >= 42) and (42 >= 42) then
writeln('42 is equal to or larger than both 42 and 43');

Lesser than
:::::::::::

The **<** operator returns true if the first value is smaller than the second
value:

.. code-block:: pascal

if 42 < 43 then
writeln('42 is smaller than 43');

Lesser than or equals
~~~~~~~~~~~~~~~~~~~~~

The **<=** operator returns true if the first value is smaller than *or equal
to* the second value:

.. code-block:: pascal

if (42 <= 42) and (42 <= 43) then
writeln('42 is smaller than or equal to 42 and 43');

Pointer Operators
~~~~~~~~~~~~~~~~~

- @
- ^

The **@** operator returns the memory address of a variable, whereas the **^**
operator retrieves the value from a memory address:

.. code-block:: pascal

var
ip: ^Integer;
i: Integer;

begin
i := 41;
ip := @i;
ip^ := ip^ + 1;
writeln(i);
end;

Mathematical Operators
~~~~~~~~~~~~~~~~~~~~~~

Addition
::::::::

The **+** operator performs an addition, note that it does not have to be a
numerical addition.
The **+** operator can be defined for other types with `Operator Overloading`_.

.. code-block:: pascal

writeln(40+2); // Integer addition adds two numbers.
writeln('Hello, ' + ' World'); // String addition concatenates strings

.. TODO: On arrays? Custom types?


Subtraction
:::::::::::

The **-** operator performs a subtraction:

.. code-block:: pascal

writeln(44-2); // Integer substraction.

.. TODO: Arrays? Custom types?

Multiplication
~~~~~~~~~~~~~~

The **\*** operator


.. ***

Division
::::::::

- /
- DIV

The **/** operator performs a division:

.. code-block:: pascal

writeln(84/2);
writeln(1/3);
writeln(1/3.0);
.. TODO: Vershil tussen DIV en /

Power Operator
::::::::::::::

The **\*\*** operator performs the mathematical power operation:

.. ***

.. math::

a^b

Where *a* is the first value; and *b* the second value:

.. code-block:: pascal

writeln(2**8);

Logical Operators
~~~~~~~~~~~~~~~~~

Logical AND
:::::::::::

The **AND** operator takes two logical values (or constructs that *evaluate*
to a value) and *evaluates* to *True* if both these values are *True*, otherwise
it evaluates to *False*.

Truth table for the **AND** operator (treat A and B as logical
values/constructs):

===== ===== =======
Inputs Output
------------ -------
A B A and B
===== ===== =======
False False False
True False False
False True False
True True True
===== ===== =======

Logical OR
::::::::::

The **OR** operator takes two logical values (or constructs that *evaluate*
to a value) and *evaluates* to *true* if any of these values are *true*,
otherwise it evaluates to *false*.

Truth table for the **OR** operator (treat A and B as logical
values/constructs):

===== ===== ======
Inputs Output
------------ ------
A B A or B
===== ===== ======
False False False
True False True
False True True
True True True
===== ===== ======

Logical XOR
:::::::::::

The **XOR** operator takes two logical values (or constructs that *evaluate*
to a value) and *evaluates* to *True* if *(only) one* of these values is true
otherwise it evaluates to *False*.

Truth table for the **XOR** operator (treat A and B as logical
values/constructs):

===== ===== =======
Inputs Output
------------ -------
A B A xor B
===== ===== =======
False False False
True False True
False True True
True True False
===== ===== =======

Logical NOT
:::::::::::

The **NOT** instruction negates the value that follows:

========= =====
not True False
not False True
========= =====

Bit Operators
~~~~~~~~~~~~~

Bitwise NOT
:::::::::::

The **NOT** operator inverts all the bits.

.. code-block:: pascal

writeln(not -43);
..

Bitwise AND
:::::::::::

The **AND** operator performs a logical AND operation on each bit of the two
input numbers.

.. code-block:: txt

001010 and 101010 = (0 and 1)(0 and 0)(1 and 1)(0 and 0)(1 and 1)(0 and 0) = 001010

Usage:

.. code-block:: pascal

writeln(10 and 42); // results in 10
..

Bitwise OR
::::::::::

The **OR** operator performs a logical OR operation on each bit of the two
input numbers.

.. code-block:: pascal

writeln(32 or 10); // results in 42
..

Bitwise XOR
:::::::::::

The **XOR** operator performs a logical XOR operation on each bit of the two
input numbers.

.. code-block:: pascal

writeln(5 xor 5);
..


Bitwise SHL
:::::::::::

The **SHL** operator performs a left shift by n bits on the first value, where n
is the second value.

.. code-block:: pascal

writeln(21 shl 1);
// 21 = '0b10101'
// 42 = '0b101010'
..

Bitwise SHR
:::::::::::

The **SHR** operator performs a right shift by n bits on the first value, where
n is the second value.

.. code-block:: pascal

writeln(84 shr 1);
..

Getting and Setting individual bits
:::::::::::::::::::::::::::::::::::


Functions and Procedures
------------------------



Functions
~~~~~~~~~





Procedures
~~~~~~~~~~



Function and Procedure overloading
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Default Parameters
~~~~~~~~~~~~~~~~~~


Records and Custom Types
-------------------------

Custom Types
~~~~~~~~~~~~

Records
~~~~~~~

Operator Overloading
~~~~~~~~~~~~~~~~~~~~


Nested Declarations
-------------------


Loops
-----

For Loop
~~~~~~~~

Repeat-Until Loop
~~~~~~~~~~~~~~~~~

While-Do Loop
~~~~~~~~~~~~~

Pointers
--------

Exceptions
----------

mastaraymond

2011-10-22 13:40:08

Ha, Niels, this is looking awesome, keep it up!

nielsie95

2011-11-05 09:33:57

I took the liberty to try and compile SRL5 with Lape. There were less errors than I initially thought. You can see my changes here. Most of the errors were just missing semicolons or semicolons in places where they didn't belong (mostly after begins.. Raymond :p). Other errors were missing definitions, as can be seen in SRLLape.simba. Font and colour constants being the most important ones.

My goal was not to get SRL working, just to get it compile, so I added semicolons and headers of missing functions, commented the parts where labels were used (2 login functions and 1 banking function), changed ToStr to ToString and changed ClickLeft..Nothing to aoClickleft..aoNothing. Everything up until the randoms can compile now :) If someone wants to do the rest, we might even try to get a working copy going!

In the progress I also found some bugs in Lape, which means the code above will only work if you have an up to date version of Simba with an up to date version of Lape. These bugs could've been found sooner ;) Mopar is hosting a version of Simba with Lape so feel free to fool around and let me know if you find anything unusual.

mastaraymond

2011-11-05 09:40:14

From: nielsie95
I took the liberty to try and compile SRL5 with Lape. There were less errors than I initially thought. You can see my changes here. Most of the errors were just missing semicolons or semicolons in places where they didn't belong (mostly after begins.. Raymond :p). Other errors were missing definitions, as can be seen in SRLLape.simba. Font and colour constants being the most important ones.

My goal was not to get SRL working, just to get it compile, so I added semicolons and headers of missing functions, commented the parts where labels were used (2 login functions and 1 banking function), changed ToStr to ToString and changed ClickLeft..Nothing to aoClickleft..aoNothing. Everything up until the randoms can compile now :) If someone wants to do the rest, we might even try to get a working copy going!

In the progress I also found some bugs in Lape, which means the code above will only work if you have an up to date version of Simba with an up to date version of Lape. These bugs could've been found sooner ;) Mopar is hosting a version of Simba with Lape so feel free to fool around and let me know if you find anything unusual.

Sorry, it's a bad habit! :redface:

Wizzup?

2011-11-05 09:46:09

You also have to update the commit the lape git-submodule points to. I did this for the simba-next and lape-integration branches just now. build by mopar should be there in 10 minutes.

Nava2

2011-11-05 10:53:08

This.. is so exciting.

nielsie95

2011-11-11 06:29:05

I got SRL through the parsing stage now, but it looks like some declarations aren't the same as in PS or perhaps there are still some bugs left in Lape that are causing this.

In other news: I made it easier to add methods of types/objects. They can also be declared in script now :)


function Integer.Hoi: Integer;
begin
WriteLn('Hoi: ', Self);
Result := Self + 1;
end;

function Integer.Hoi: Integer; override;
begin
WriteLn('Lols!');
Result := inherited;
end;

begin
WriteLn(1.Hoi.Hoi);
end;

Not sure what type the self parameter is going to be; either var or const. If it's var, you could change "1" to every other number in the above example. If it's const, you can only modify vars by returning a new version (might not be what you want when working with records or arrays).

Classes could be imported as a pointer type with extra methods, although properties and the class operators is and as wont work yet.

Wizzup?

2011-11-11 07:30:43

Awesome! :)

Nava2

2011-11-17 23:47:42

23:45 <@Jason2gs> Gurooni, Google agrees with you that it's normally array
[1..9,1..9] of Integer;
23:45 <@navatwo> but in FPC you can do: X: T2DIntegerArray; SetLength(x, 9, 9(;
23:45 < Gurooni> yeah, that was what was tricking me up
23:45 <@navatwo> PS' bullshit
23:45 < Gurooni> tripping
23:45 <@Jason2gs> But array [1..9][1..9] of Integer also works. Just not in
Simba's pascal implementation.


Thought it was something that was probably not thought of.

nielsie95

2011-11-18 02:32:28

The declarations will not work, but the SetLength should. Compatibility with FPC/Delphi is not really a big issue. There are a lot of things you can do in FPC, but not in Lape/PS.

nielsie95

2011-11-20 08:09:15

Alright! SRL compiles now! =D
You'll need the latest Simba (Lape branch) and the latest SRL (SRL 5, Lape branch).

I added a 'loose semicolons' option, which should allow less strict usage of semicolons (a la PS). This means I only had to add one extra semicolon to SRL. I also changed the name of 'Move' to 'MemMove' in Simba, instead of changing the mouse enums (Move, ClickLeft, etc) in SRL. The only things that had to be removed were labels and classes. This means that these parts in SRL are now wrapped in compiler directives (login function(s), a banking function, random form).

Downside: compiling takes about 3.5 minutes :p

Markus

2011-11-20 08:27:56

210 seconds, that's 200 times as slow as PS on a bad day… How's execution speed? Is it possible to precompile SRL and link scripts to that? That would really save a lot of time (and I'd love the feature myself, for some future project).

nielsie95

2011-11-20 08:31:54

It could be done, but it's not really what you want because of features like function overriding. What do you want to know about execution speed? Feel free to run some benchmarks :)

mastaraymond

2011-11-20 08:42:43

From: Markus
210 seconds, that's 200 times as slow as PS on a bad day… How's execution speed? Is it possible to precompile SRL and link scripts to that? That would really save a lot of time (and I'd love the feature myself, for some future project).

Oh oh oh, you're in it for the money! Sneaky bastard.

Markus

2011-11-20 09:52:05

From: mastaraymond
Oh oh oh, you're in it for the money! Sneaky bastard.


My boss left, his replacement is almost like a Nazi, watching the security cams all the time to spy at his employees #illegal.

Sir R. M8gic1an

2011-11-20 10:05:16

From: Markus
My boss left, his replacement is almost like a Nazi, watching the security cams all the time to spy at his employees #illegal.


Hack into the system put a static photo on where the camera's supposed to be filming?

-RM

Nava2

2011-11-20 11:07:16

From: nielsie95
It could be done, but it's not really what you want because of features like function overriding. What do you want to know about execution speed? Feel free to run some benchmarks :)


Wait.. it takes 210s to compile..?

Is that because of the semi-colons?

nielsie95

2011-11-20 11:38:28

I guess that's one of the reasons, yes. I don't know how much faster it would be without that option, but it still wouldn't be 1s ;)

Coh3n

2011-11-20 14:14:53

So why does it take so long?

nielsie95

2011-11-21 14:28:36

It probably does a lot of unneeded work, with a lot of overhead. There's plenty of room for optimization ;)

Wizzup?

2011-11-25 13:33:28

formWriteln: Compiled successfully in 213447 ms.
formWriteln: SRL Compiled in 1 msec
formWriteln: Successfully executed.

SRL-5 on Linux, x86-64. :)

Nava2

2011-11-25 14:43:19

From: Wizzup?
formWriteln: Compiled successfully in 213447 ms.
formWriteln: SRL Compiled in 1 msec
formWriteln: Successfully executed.

SRL-5 on Linux, x86-64. :)


That's awesome, but that's 4 minutes…

Wizzup?

2011-11-26 09:37:54

From: Nava2
That's awesome, but that's 4 minutes…


Nielsie said there would be room for improvements, and I agree with him. If you have some free time, perhaps have a look at the compiler?

nielsie95

2012-01-02 19:12:12


Compiled successfully in 12231 ms.
SRL Compiled in 0 msec
Running Lape!
Successfully executed.

I might have introduced some bugs along the way (I hope not), but it's a start :)

Wizzup?

2012-01-02 19:22:23

Great! Once I have FPC 2.6.0 working with Simba I will post new benchmarks from x86_64 Linux.

nielsie95

2012-01-04 11:23:06

Already fixed a few bugs that have been caused by the optimizations, but there might be more (feel free to test!).

Current compilation time of SRL with Lape is 1370ms versus 530ms with Pascal Script. There are still a few bottlenecks that I know of, though. This is workable for now, no?

noidea

2012-01-04 18:33:14

Just wondering, what is the point of an is operator? I find it quite irritating in Python (considering it's 'one way to do something' ideology). Isn't it good enough to use =, or does it not apply amongst multiple variable types?

Wizzup?

2012-01-04 18:42:41

From: noidea
Just wondering, what is the point of an is operator? I find it quite irritating in Python (considering it's 'one way to do something' ideology). Isn't it good enough to use =, or does it not apply amongst multiple variable types?


is is for type comparison, afaik.

Wizzup?

2012-01-04 18:43:16

From: nielsie95
Already fixed a few bugs that have been caused by the optimizations, but there might be more (feel free to test!).

Current compilation time of SRL with Lape is 1370ms versus 530ms with Pascal Script. There are still a few bottlenecks that I know of, though. This is workable for now, no?


(Double post): Amazing work… Very workable.

NCDS

2012-01-05 08:32:43

From: nielsie95
Already fixed a few bugs that have been caused by the optimizations, but there might be more (feel free to test!).

Current compilation time of SRL with Lape is 1370ms versus 530ms with Pascal Script. There are still a few bottlenecks that I know of, though. This is workable for now, no?


Awesome!


Wow, this has really made some progress while I was gone. Nice job. :)

noidea

2012-01-05 19:02:20

From: Wizzup?
is is for type comparison, afaik.


You mean it should be used for type comparison (Specific to Simba and/or Python)?

>>> a = 33
>>> a is 33
True
>>> a == 33
True
>>> b = '33'
>>> 33 is b
False
>>> 33 == b
False
>>> 33 == int(b)
True
>>> 33 is int(b)
True

Wizzup?

2012-01-05 19:17:40

From: noidea
You mean it should be used for type comparison (Specific to Simba and/or Python)?


You're comparing types. If you look at the example, you'll find that is compares types.

Daniel

2012-01-05 22:45:29

From: noidea
You mean it should be used for type comparison (Specific to Simba and/or Python)?


With the is keyword, you are testing to see if a variable's type (NOT the value(s) it is assigned) is the same as another, belongs to a class or a parent of that class.

e.g., assuming Sender is a TButton type:

if(Sender is TButton) then
….

if(Sender is TObject) then
….


Both will equal to true. Because a TButton is a child of the TObject class. If you look at the source:
type
TButton = class(TObject)

noidea

2012-01-05 23:25:26

From: Daniel
With the is keyword, you are testing to see if a variable's type (NOT the value(s) it is assigned) is the same as another, belongs to a class or a parent of that class.

e.g., assuming Sender is a TButton type:

if(Sender is TButton) then
….

if(Sender is TObject) then
….


Both will equal to true. Because a TButton is a child of the TObject class. If you look at the source:
type
TButton = class(TObject)



Great explanation. It's the same as Wizzup told me about on irc. I guess Python's is slightly different. It seems to be comparing values.


lucas@dbox3:~$ python
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 33
>>> a is 33
True
>>> a == 33
True
>>> b = '33'
>>> 33 is b
False
>>> 33 == b
False
>>> 33 == int(b)
True
>>> 33 is int(b)
True
>>> a is 5
False
>>> a
33

Dgby714

2012-01-05 23:34:56

From: noidea
Great explanation. It's the same as Wizzup told me about on irc. I guess Python's is slightly different. It seems to be comparing values.


It may also just be testing the type of the variable against the type of the constant.

Try:

a = 33
b = 34
a is b

If it is True, then it is testing types.
If it is False, then values.

noidea

2012-01-06 20:54:42

From: Dgby714
It may also just be testing the type of the variable against the type of the constant.

Try:

a = 33
b = 34
a is b

If it is True, then it is testing types.
If it is False, then values.


Thats what I was saying :p

>>> a = 33
>>> b = 34
>>> a is b
False


Niels - sorry for highjacking your thread!

nielsie95

2012-01-23 14:52:07

Wizzup helped me to merge the latest SRL with the Lape branch, so the latest SRL compiles again now. It even logged me in!

Most of the compilation errors came from:
  • Int / 2 does not return an integer! Int div 2 does!
  • Integer(Boolean) is an invalid cast! Use Ord(Boolean).
The fixes for these issues will also work in Pascal Script, so perhaps you should try to use the method that works in both interpreters from now on :)

I also added swap() and labels:

var
x: label;
begin
goto(x);
WriteLn('hai');
label(x);
WriteLn('bai');
end;

Perhaps I'll make a setting to make it compatible with pascal syntax.

EDIT:
Added the option to allow default Pascal syntax for labels. This is a compiler define (for Lape, not for in the script).

Markus

2012-01-26 06:08:12

SRL compiles and can log in. Does that mean SRL is functional or did you have to comment quite a lot out?
I could just run a simple chicken killer to test Lape, but if antirandoms don't work that would be a bit useless..

nielsie95

2012-01-26 06:28:07

This was needed to get SRL to compile. Not a whole lot is commented out, although ChooseOption is still missing an important function I believe. Plugins also wont work, so SMART or randoms that need plugins wont work either. Perhaps simple scripts will work :)

Markus

2012-01-26 06:44:08

All plugin randoms atm are already broken (irokiplugin is and that's the only random plugin afaik) so that doesn't matter :) SMART isn't necessary to auto so in that case it should be suitable for testing, right?

nielsie95

2012-01-26 06:59:29

Yup :)

HyperSecret

2012-01-26 09:29:35

Very sexy man, keep up the great work!

nielsie95

2012-03-03 13:47:12

Last month was mostly spend on debugging. I created a decent number of test cases and a test runner. Also fixed quite a few bugs (thanks to dgby for finding a few of them). I think Lape is reaching quite a workable stage.

Let's see how Project Sigma will turn out. I'm hoping on a lot of entries; perhaps I'll try some myself too. So if you have a free 15 minutes and want to help/try Lape, please enter the competition! It's also a good practice for those of you who have been out for quite some time! You could also try to do them on Linux if you want.

Daniel

2012-03-06 04:49:47

Hey Niels,

Just thought I'd let you know, but the compiling time when loading a large array isn't that great :-/ At the moment I'm trying to load an array which has ten thousand elements, however it's been ~10 minutes and nothing, just a high CPU usage.

Could you please check this out?

Regards,
Daniel. :)

(Using latest nightly build of the master branch, as-well as the latest stable release)

Just to note, PascalScript doesn't have this problem.

nielsie95

2012-03-06 14:12:32

Try loading it as a static array (you can still assign it to a dynamic array). You're right that it is slow, though.


var
b: array of Integer = [1..1000];

is a lot slower than


var
a = [1..1000]; //This will be a static array -- you can also make this a constant
b: array of Integer;
begin
b := a;
end;

I'll see what I can do. :)

EDIT:
Assuming you are loading 'randomized' arrays. You could also do it using a for loop with a preset randseed.


begin
RandSeed := 0;
for 1 to 10 do
Write(Random(5), ' ');
WriteLn();
end;

Will always return the same list of random numbers (0 0 4 2 2 2 0 4 4 2, …).

Daniel

2012-03-06 21:14:18

From: nielsie95
Try loading it as a static array (you can still assign it to a dynamic array). You're right that it is slow, though.


var
b: array of Integer = [1..1000];

is a lot slower than


var
a = [1..1000]; //This will be a static array -- you can also make this a constant
b: array of Integer;
begin
b := a;
end;

I'll see what I can do. :)

EDIT:
Assuming you are loading 'randomized' arrays. You could also do it using a for loop with a preset randseed.


begin
RandSeed := 0;
for 1 to 10 do
Write(Random(5), ' ');
WriteLn();
end;

Will always return the same list of random numbers (0 0 4 2 2 2 0 4 4 2, …).


I wasn't aware of the RandSeed property, thanks for letting me know that it exists in Lape and can be modified :)

And what I tried to do in order to keep the same array, I just printed an array of random integers, then tried to load that in Lape and it took forever :redface: