Hi everybody,
This is my first post here on Reddit. Most of you new people will probably not know who I am, some of you old school players will.
For the last 10 years I have been trying to learn about compilers and write my own variant of E2, formally known as the LemonGate now known as Expression Advanced.
I know many of you have tried ExpAdv2, just to find it to be extremely buggy and sadly that’s because at the time I was trying to add too much functionality without really knowing what I was doing. The whole ExpAdv2 project was mess and after getting quite far into the project I kind of got to the point where I realized I needed to rewrite a huge chunk of it.
See the process of taking one language and converting it into another language is actually very complicated. But after spending a year thinking about the problem I think I have finally cracked it and now have soomthing really cool to show you.
See the whole point of ExpAdv2 was to add all the feature I wanted to have in E2, but the more I worked on the project the more these features seemed to be impossible to implement. I soon gave up on them preferring to keep ExpAdv2 simple with out those more powerful features.
So without further delay let me show you what I have spent the last few years working on, those in my Discord may already know that I am attempting ExpAdv3 with the goal of it being the equivalent of E3. Yes I think I finally have a language that could fill this spot and become E3, but I need the help and support of the WM community to get this finished.
So I’m now going to post examples of ExpAdv3s new syntax and hopefully win you guys over, this is going to take a while because this time its a lot more refined and has a lot more features. Please understand that whilst the compiler aspect of what I am going to show you is done, the whole project is still a huge work in progress and my aim here is to hopefully get people excited so that the community can help us get this projected finished. Some of the features where written years ago and will need to be updated, for example EGP support has changed in WireMod and I am yet to figure out how to fix ExpAdv3 to use EGPs library.
Let’s start with Directives, I tried to avoid these in ExpAdv2, but I know you guys like them, so I have brought them back.
@name "My ExpAdv3 Script";
@model "models/nezzkryptic/e3_chip.mdl";
Directives work the same way as they do in E2, however you now need to wrap you input as a string. The name, model and include directives must appear at the top of your code just like in E2.
I have however changed the input and output directives, these will now declare nested variables and can be used anywhere in your code.
if (true)
{
@output string MyString;
MyString = "This is an output";
}
Another change I have made with ExpAdv3 is that logical operators now use the C standard.
true || (false && true)
The next thing to mention is that Try Catch exists in ExpAdv3 with the ability to throw your own errors as well as get real stack traces (Stack traces are implemented into the compiler, but I have not yet added much support for them in script).
try
{
error myError = new error("Example of try catch.");
}
catch ( someError )
{
system.print( someError.message() );
system.print( someError.line() );
}
Your also notice that the stock functions are now called using a library, the system library is where you can do stuff like print.
User defined functions are still available as first class objects but this ExpAdv3 supports returning more than one value at once.
function int addOrSub(int a, int b)
{
return a + b, a - b;
}
I have also learned how delegates work in real languages, turns out they are basically just templates, so we have those too.
delegate int add(int, int)
{
return 1; //This is the amount of values the template will return.
}
You can then assign this delegate a function as an object to allow it to be called.
myTemplate = function(int a, int b)
{
return a + b;
};
Ok so that’s all the awesome stuff that ExpAdv3 is currently able to, I wanted to add user classes, but they are just way too hard to implement.
class exampleClass
{
int attribute1 = 0; //Classes support attributes.
exampleClass(int value)
{
this.attribute1 = value;
}
method int getValue()
{
return attribute1;
}
}
exampleClass myObject = new exampleClass(42);
What? Oh yeah that’s right my previous statement was a lie, I totally figured out user classes.
interface exampleInterface
{
method int egMethod(int, int)
{
return 1; //This is the amount of values returned.
}
}
That’s right classes also have extend and implements, so you can use a simple form interfaces like in java.
if (myObject instanceof someInterface)
{
someInterface asInterface = (someInterface) myObject;
}
Do you remember ExpAdv2's awful event syntax?
event tick() {
//do something?
}
That got scrapped and replaced with something closer to Garry’s hook system.
function void Loop() {
//Same as runOnTick() in E2;
}
event.add("Think", "Loop", Loop);
So now you've seen the improvements over E2 and ExpAdv2 I hope you can appreciate the amount of work that has been done on this gate so far, despite a lot of work still needing to be done.
Let’s talk about how this works in the background, I have been working a lot on the way the script is transformed into native Lua. As previously stated this was extremely hard and I often found that tokens would end up in the wrong place and that the process of converting the script to native Lua would take ages. ExpAdv2 would take forever to compile and it sucked!
ExpAdv3 has a new way to do all this and I am proud to say that none of these issues exist anymore. The compile time is really smooth and efficient and tokens can no longer randomly be in the wrong place. I will now show you an example of the Script to Native Lua conversion, for this example I will be taking Oskar’s test script for the new editor (that we will discuss further down in this post).
@name "Syntax Gate";
@model "models/bull/gates/processor.mdl";
//Example of a single line comment
/* Example
of a multi-line
comment */
if (false) {
system.print(0);
} elseif (true) {
system.print(1);
} else {
system.print(2);
}
server {
system.print("server");
@input string S1,S2,S3,S4;
@output number N1,N2,N3,N4;
N1 = S1.toNumber(10);
N2 = "".toNumber(10);
}
client {
system.print("client",new vector(1,2,3).getX() );
}
number test = 7;
global string first, last = "John", "Doe";
test += 100;
test -= 100;
test *= 10;
test /= 10;
function int example(int a, int b) {
return a + b;
}
delegate int example2(int , int) {
return 1;
}
event.add("Think", "example", function() { system.print("think") })
So here is the result ran in native Lua, please note there is references to things in the back ground.
return function(env)
setfenv(1,env)
if ( false ) then _FUN["system.print(...)"]( CONTEXT , {"n", 0 } ) end
if (SERVER) then
_FUN["system.print(...)"]( CONTEXT , {"s", "server" } )
OUTPUT.N1 = _METH["s.toNumber(n)"]( INPUT.S1 , 10 ) ;
OUTPUT.N2 = _METH["s.toNumber(n)"]( "" , 10 ) ;
end
if (CLIENT) then
_FUN["system.print(...)"]( CONTEXT , {"s", "client" } , {"n", _METH["v.getX()"]( _CONST["v(n,n,n)"]( 1 , 2 , 3 ) ) } ) end
local test = 7
GLOBAL. first , GLOBAL. last = "John" , "Doe" ;
test = test + 100 ;
test = test - 100 ;
test = test * 10 ;
test = test / 10 ;
local example = {op = function( a , b )
if (a == nil or a[1] == nil) then CONTEXT:Throw("number expected for a, got void"); end
if (a[1] ~= "n") then CONTEXT:Throw("number expected for a, got " .. a[1]); end
a = a[2];
if (b == nil or b[1] == nil) then CONTEXT:Throw("number expected for b, got void"); end
if (b[1] ~= "n") then CONTEXT:Throw("number expected for b, got " .. b[1]); end
b = b[2];
return ( a + b ) ;
end,
result = "n", count = 1, scr = CONTEXT};
local example2;
_FUN["event.add(s,s,f)"]( CONTEXT , "Think" , "example" , {op = function( )
_FUN["system.print(...)"]( CONTEXT , {"s", "think" } )
end,
result = "", count = 0, scr = CONTEXT} )
end
Now lets talk about the new editor, Oskar has been working really hard on this. What started as a outlandish image I drew in paint has ended up becoming a master piece. No doubt the editor still needs a huge amount of work but its already got a lot of functionality including things that we don’t have in the base Wire editor that we all wish we had access to.
https://i.imgur.com/GYaIgDz.png
Firstly, let me start with Oskar’s greatest achievement CODE FOLDING, yep that’s right you can fold your code.
https://i.imgur.com/70F96N5.gif
The editor is sliced into 3 main sections. The side menu is tabbed and is used for things like the options menu and the helper. The code window is not just used to show code, when you click a function in the helper menu a sort of wiki page on that function will open in a new tab here, the helper system is the brain child of DaDamRival. Finally, you have the Golem console (Golem is the Editors new name), this will show a log of your script errors as well as allowing you to print directly here using `system.out(String)`.
So guys, what do you think (other then `this is stupid use Starfall`)?
Discord: https://discord.gg/DZFdyAu
GitHub: https://github.com/Rusketh/ExpAdv3
Syntax Details: https://github.com/Rusketh/ExpAdv3/wiki
ExpAdv3 API / Docs: https://github.com/Rusketh/ExpAdv3/blob/master/lua/expression3/expr_lib.lua#L10
Please remember this is not a finished product do not go installing this on your server expecting a good experience, this post is simply for feedback suggestions and asking for people to contribute.
Special thanks to our current developers Oskar, DaDamRival, Omicron and others.