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.
var
while
if
if, else if, else
return
import
An lvalue is a stored value, with an identifier, such as a variable.
The following code qualifies as an lvalue: (Underlined code = 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)
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)
'script.ep'
'main.cpp'
'main.cpp'
'script.ep'
Console output running 'main.cpp'
Before optimization
After return omit optimization
After return omit, and empty non-modifying expressions omit optimization
After return omit, empty non-modifying expressions omit, and constant folding optimization
Please post if you would want to use it, and what you think should be changed just from reading this post.
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
methodCode:
method identifier( arguments... )
{
// Return value is optional.
}; // Important note, semicolon needed
Code:
var variable_identifier; var variable_identifier = expression;
Code:
while ( expression )
{
[...]
}
// or
while ( expression )
statement;
Code:
if ( expression )
{
[...]
}
// or
if ( expression )
statement;
Code:
if ( expression )
{
[...]
}
else if ( expression )
{
[...]
}
else
{
[...]
}
// or
if ( expression )
statement;
else if ( expression )
statement;
else
statement;
Code:
return expression;
Code:
import library_name;
Semantics
lvalueAn 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;
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;
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 );
};
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;
}
}
Code:
import lib; import ios; // print_methods var test; method_name( 25 ); method_name( "hi" ); method_name( test ); print_methods( );
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;
};
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;
};
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;
};
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;
};
Thanks,
Yamiez.
Yamiez.


