EP0x Scripting Language, interesting?

Posts 112 of 12 · Page 1 of 1
EP0x Scripting Language, interesting?
I've been pretty bored in school recently, most of the stuff is suuuuper easy, so I decided to create a simple scripting language.

Expression Parser
Current version: ep0x
The language has 7 keywords, they can be seen in the following list:
  • method
  • var
  • while
  • if
  • else
  • return
  • import


Examples
method
Code:
method identifier( arguments... )
{
    // Return value is optional.
}; // Important note, semicolon needed
var
Code:
var variable_identifier; 
var variable_identifier = expression;
while
Code:
while ( expression )
{
     [...]
}
// or
while ( expression )
     statement;
if
Code:
if ( expression )
{
     [...]
}
// or
if ( expression )
    statement;
if, else if, else
Code:
if ( expression )
{
    [...]
}
else if ( expression )
{
    [...]
}
else
{
    [...]
}
// or
if ( expression )
   statement;
else if ( expression )
   statement;
else
   statement;
return
Code:
return expression;
import
Code:
import library_name;
Semantics
lvalue
An lvalue is a stored value, with an identifier, such as a variable.
The following code qualifies as an lvalue: (Underlined code = lvalue)
Code:
function( variable_identifier );
var lvalue = variable_identifier;
lvalue;
rvalue
An rvalue is a temporary value, without an identifier, such as an expression.
The following code qualifies as an rvalue: (Underlined code = rvalue)
Code:
function( 5 + 10 );
var lvalue = function( 10 ) + 200;
5 + 5;
References
A reference, is a variable that keeps a value reference to another variable. Currently as of version ep0x references only exists as arguments. (Underlined = reference)
Code:
method function( &reference, copy )
{
    reference = 201;
    copy = 201;
};
var ref = 200;
var copy = 200; 
function( ref, copy );
// At this point ref is equal to 201, whilst copy is equal to 200 still.
Comments
As of version ep0x there are only one lined comment available, example:
Code:
// Comment stuff goes here
Usage in C++
The usage from the developers end is actually, very easy. You can call any method defined in your script directly from C++, you can either have the module build a std::function object for you, or have the module directly call it for you.

'script.ep'
Code:
import bo; // operator+.
import ios; // println.

method ep_method( &message )
{
    println( "in ep script, message: " + message );
};
'main.cpp'
Code:
#include <ep/ep.h>

void main()
{
     auto module = std::make_shared<ep::module>( );
     try 
     {
          module->eval_file( "script.ep" );    
     }
     catch( ep::eval_error &err )
     {
          std::cout << err.pretty_format( ) << std::endl;
          return;
     }

     auto function_object = module->get_method_object<void( const std::string& )>( "ep_method" );
     // Call it right here in C++
     function_object( "Call from a function object." );
     
    // Call it directly with the module
    module->call_method<void>( "ep_method", "Call directly from module ptr" );
}
Creating a library for ep0x
Creating a library for ep0x is fairly complex, but as of ep0x this is the only way you can do it.
'main.cpp'
Code:
#include <ep/ep.h>

void main( )
{
	auto library = []( ep::dispatch_engine_ptr engine )
	{
		// Adding a method
		engine->add_method( std::make_shared<ep::method>( "method_name",
			            ep::method_argument_list{ std::make_shared<ep::method_argument>( "arg_name" ) },
				    []( ep::variable_list args, ep::dispatch_engine_ptr engine )
		{
			auto vref = args[0]->get_ref( ); // This is safe because, "method_name" will NEVER be called with too few arguments.
			// However the type is not checked by the callee.
			if ( vref->is_floating( ) ) // int, double, or pointers.
				std::cout << vref->get_value( ) << std::endl;
			else if ( vref->is_string( ) ) // String value
				std::cout << vref->get_string_value( ) << std::endl;
			else if ( !vref->is_initalized( ) )
				std::cout << "<undefined-behaviour>" << std::endl;
                    return ep::void_return;
		} ) );
	};

	auto module = std::make_shared<ep::module>( );
	try
	{
		module->add_lib_fun( "lib", library ); // Whenever you do "import lib;" in ep code library will be called.
		module->eval_file( "script.ep" );
	}
	catch ( ep::eval_error &err )
	{
		std::cerr << err.pretty_format( ) << std::endl;
	}
}
'script.ep'
Code:
import lib;
import ios; // print_methods

var test;
method_name( 25 );
method_name( "hi" );
method_name( test );
print_methods( );
Console output running 'main.cpp'
Code:
25
hi
<undefined-behaviour>
-->> Method table:
---->> method_name( arg_name )
---->> print( x )
---->> println( x )
---->> print_methods( )
---->> fopen( &fname, &ftype )
---->> fclose( &fhandle )
---->> feof( &fhandle )
---->> fgetline( &fhandle, &soutput )
Optimization
Optimization is a pretty big part of this because in order for the runtime to have as little overhead as possible we need to optimize away useless blocks, and also do constexpr calculations. The optimization is broken into 3 segments, they are as following: return omit, empty non-modifying expressions omit, and constant folding.

return omit
return omit, works by omitting all the code that comes after a return statement, in that scope only.
Before optimization
Code:
import bo; // Basic operations

method function( a, &b, &c )
{
    if ( a > b )
    {
        b * a;
        return a + b;
        b = a + 200;
    }
    else if ( a > c )
    {
        c * a;
        return a + c;
        c = a + 300;
    }
    a = a + 10 * 10;
    a + c * b;
    return a + b + c;
    a = 200 + b * c;
};
After return omit optimization
Code:
import bo; // Basic operations

method function( a, &b, &c )
{
    if ( a > b )
    {
        b * a;
        return a + b;
    }
    else if ( a > c )
    {
        c * a;
        return a + c;
    }
    a = a + 10 * 10;
    a + c * b;
    return a + b + c;
};
After return omit, and empty non-modifying expressions omit optimization
Code:
import bo; // Basic operations

method function( a, &b, &c )
{
    if ( a > b )
        return a + b;
    else if ( a > c )
        return a + c;
    a = a + 10 * 10;
    return a + b + c;
};
After return omit, empty non-modifying expressions omit, and constant folding optimization
Code:
import bo; // Basic operations

method function( a, &b, &c )
{
    if ( a > b )
        return a + b;
    else if ( a > c )
        return a + c;
    a = a + 100;
    return a + b + c;
};
Please post if you would want to use it, and what you think should be changed just from reading this post.



Thanks,
Yamiez.
Good job. Keep it up.
Quote Originally Posted by Lols12342 View Post
Good job. Keep it up.
It's not a release, atleast not yet. I'd prefer comments on improvements and or if you even want it to be released.
nice moves yammi, keep it upp!
Misjudged, no need for a complete rewrite. I was able to fix now after waking up, I guess I was just being stupid tired.

Currently implementing:
TBA
Dunno if anybody actually care much of this at the moment, but currently working on variable method/member access, such as:

Done, the following code is now fully working:
Code:
import bo;
import ios;
import vector;
import string;

autp vec = vector();
vec->emplace_back( "value" );
vec->emplace_back( "=" );
vec->emplace_back( "25" );
vec->emplace_back( ";" );

auto it = vec->begin( );
auto end = vec->end( );
while( it->less( end ) )
{
	println( it->access() );
	it->increment( );
}
Output:
Code:
value
=
25
;
ep1x changelog:
Code:
- Added 'auto' keyword, only usable when the variable is initialized.
- Fixed optimization bug (it would remove statements like: it->increment() )
- Added one new operator '->', use when accessing a variables public members or methods.¨
- Added three new default libraries: 'string', 'vector', and 'parsing'.
- Code optimization (moving instead of copying, mainly)
ep1x1 changelog:
Code:
- Actually enforce the 'auto' keyword rules now, lol.
- Added type system (e.g dispatch_engine::get_type_info)
- Lots of optimization with types and methods
- Removed variable members (Now only methods are available)
- Improved error messages.
- Improved standard libraries.
So if I got this right this is a scripting language which (in the future) I can use for example my cheat?

I want a scripting language support in my wow bot
Quote Originally Posted by gtaplayer2 View Post
So if I got this right this is a scripting language which (in the future) I can use for example my cheat?

I want a scripting language support in my wow bot
Yep, a scripting language that can be used a long side C++.

ep1x1 is soon ready for a first time test release, I just need to write up all the information and stuff.

I already know you, so feel free to add my Discord and I can let you test it out ^^
Quote Originally Posted by Yemiez View Post
Yep, a scripting language that can be used a long side C++.

ep1x1 is soon ready for a first time test release, I just need to write up all the information and stuff.

I already know you, so feel free to add my Discord and I can let you test it out ^^
Yamiez#8430 right?
Can't add it, never used discord before.

Mine is Luciz#2438
Quote Originally Posted by gtaplayer2 View Post
Yamiez#8430 right?
Can't add it, never used discord before.

Mine is Luciz#2438
Oh shit, yea it's Yemiez#8430 lmao, my bad.
Added you though
Making an elegant type-system is hard, I have completely revamped the internal representation of a value now, it works a long side a type.

And as such, whenever you do something like:
Code:
a + b;
The method '+' in 'a' will be called with the argument 'b'.

I've also started to work on a more developer friendly interface, making the process completely automatic and having each type deduced from the argument list.
I would recommend any currently sane person not to read the code, you wont be very sane afterwards.
Example using the new interface:
Code:
int main( int argc, char **argv )
{
	auto module = std::make_shared<ep::module>( );
	module->add_lib_fun( "testing",
						 []( ep::dispatch_engine_ptr &engine )
	{
		struct tester
		{
			tester( const int &x )
				: x_( x )
			{ }

			void print( )
			{
				std::cout << "tester::print " << x_ << std::endl;
			}

			int x_;
		};

		ep::add_type( engine,
					  "tester",
					  [engine]( const int &x )->ep::value_reference_ptr
		{
			auto vref = std::make_shared<ep::value_reference>( new tester( x ), engine->get_type_info( "tester" ) );
			return std::move( vref );

		},
					  []( ep::value_reference *ptr )->void
		{
			delete ptr->get_pointer<void>( );
		},
			[]( ep::value_reference *ptr )->ep::value_reference_ptr
		{ 
			return std::make_shared<ep::value_reference>( new tester( *ptr->get_pointer<tester>( ) ),
														  ptr->type_info( ) );
		},
			// Below you can add an indefinite amount of member functions
			// as long as they match the pattern of ( Str, Callable, Pattern... )
			// Where Str is something a std::string can be constructed from,
			// where Callable is a function object, and
			// where Pattern... is the above repeated an EVEN amount of times.
			"print",
			[]( tester *obj )
		{
			obj->print( );
		} );
	} );

	module->eval( R"(
			import testing;
			auto val = tester( 5 );
			val->print( );)" );
	std::cin.get( );
}
Posts 112 of 12 · Page 1 of 1

Post a Reply

Similar Threads

Tags for this Thread

None

Need help?