- a programming language which does not try to rebuild the wheel , it uses the wheel . based on custom algorithms which tries to be simple , fast , extensible and efficient with Goal of creating a language which can be anything from config language to general purpose programming language .
- fast runtime
- simple syntax
- extensible
- dependency free
- memory safety at its core without garbage collection !
- build :
git clone https://github.com/SkillfulElectro/JuaLang.git
mkdir build
cmake -S . -B build
cmake --build build --config Release- just include the JuaLang.h file from include directory and link your program to shared lib in the build directory .
-
JuaLang has very similar syntax to other programming languages like JavaScript , the functionality of the below JuaLang codes are same as JavaScript
-
preprocessors : preprocessors are extensions to language syntax ! anything between # and ; is a code block which will be preprocessed .
#import("main.jua");- comments :
/*comment */- loops (only while loop is supported) :
while (condition) {
continue;
break;
/*code*/
} - if else chain :
if (condition) {
/*code*/
} else if (condition) {
/*code*/
} else {
/* code */
}- macro definition :
macro func_name(args) {
/* code */
}
in future updates , function keyword will be used for defining functions instead of macros .
function func_name(args) {
/* code */
}- function / macro calling :
func_name(args ...);- member function calling (only objects of JuaVoidType) :
/*if x is JuaVoidType the below code is valid*/
x.func_name(args ...);- variable definition : JuaLang only supports two data types numeric and strings !
hi = "string data type"
numeric = 1.2 - expressions :
/*you can use macro functions like below because they do not return values !*/
value = 2;
squared = 0;
square(value , squared);
hi = zed() + (4/2) * 3 / (x.beta(3) - 6) + squared;- return : unlike other languages , in JuaLang return is global keyword which is used for adding values to final result of running code .
return x , 2 , ...;- for extending Jua , you have two ways :
- the easiest way to extend Jua is by using JuaFunc .
- you only have to define a function with same signature as the below example and then in your code you can use it like other built-in functions . (unlike macros , they return values which)
#include "JuaLang.h"
JuaOprand jua_extension_func(std::vector<JuaStackVal>& oprands) {
for (size_t i = 0 ; i < oprands.size() ; ++i) {
auto& oprand = *oprands[i].get_ptr();
switch (oprand.op_type)
{
case STRING:
std::cout << oprand.get_str() << "\n";
break;
case DOUBLE:
std::cout << oprand.get_doub() << "\n";
break;
}
}
JuaOprand ret {VOID , nullptr};
ret.destructor = [](JuaOprand*) {
std::cout << "cleaning ! \n";
};
return ret;
}- below code adds print function to JuaLang interpreter : (it is suggested to use set_interpter on your JuaLang compiler instance before running compilation task !)
JuaLang cinstance;
JuaInterpter instance;
instance.add_extension("print", jua_extension_func);
cinstance.set_interpter(&instance);- also set_interpter is used to check function availability in the interpreter side .
- if you want to add objects to JuaLang , you can create classes which inherit from JuaVoidType and override virtual functions .
- JuaVoidType class :
class JuaVoidType
{
public:
// params[0] is JuaVoidType* which ref to class itself
virtual JuaOprand run_func_by_symbol(const std::string& , std::vector<JuaStackVal>&) = 0;
virtual bool is_copyable() {
return false;
}
virtual JuaOprand copy() {
return {DOUBLE , 0.0};
}
virtual bool is_equatable() {
return false;
}
virtual bool equals(JuaVoidType*) {
return false;
}
virtual bool is_hashable() {
return false;
}
virtual size_t hash() {
return 0;
}
};- after creating your class , now you can expose your class objects using JuaFunc .
- for example below function is used to create instance of JuaStdMath class in JuaLang :
// importer: pushes a void‑typed math object onto the stack
inline JuaOprand jua_std_math_importer(std::vector<JuaStackVal>& oprands) {
JuaOprand ret{ VOID, new JuaStdMath };
ret.destructor = [](JuaOprand* obj) {
delete obj->get_void_ptr();
};
return ret;
}- are same as JuaFunc but they run on compile time !
- for example import is a preprocessor which is defined by Jua standard library :
#import("../main.jua");- you create them by defining a function in signature same as below function :
std::string import(const std::vector<DFActionToken>& tokens) {
// ...
}- by the way , it must return valid JuaLang code !
- so overall it gets the tokens directly and creates special behavior for them in compile time !
- you add your preprocessor to your compiler instance like below example :
JuaLang cinstance;
cinstance.preprocessors["import"] = import;
cinstance.preprocessors["include"] = import;- now its possible to use them in JuaLang code .
- Jua compiler for
hi = 10;
while (hi - 1) { bye(hi); hi = hi - 1; }
return hi;
- generates juax code like below
= #10 ; 1
= 1 ; 0
= #1 ; 2
- 0 2 3
jmpf 3 11 ;
push 0 ; ;
call bye 1 4
= #1 ; 5
- 0 5 6
= 6 ; 0
jmp 2 ; ;
push 0 ; ;
ret 1 ; ;
- but you can use other functions of the JuaLang instance to introduce new functionality
- sample compilation cpp code :
JuaLang instance;
std::cout << instance.compile("hi = 10; while (hi - 1) { bye(hi); hi = hi - 1; } return hi;");- when you use set_interpter function , it produces faster Juax code for available interpreter , btw if you want to produce general Juax code do not use this function
- all contributions are welcome .
- lexer init
- Jua native function creation
- Jua native function calls
- function calls
- function return type
- mixing up functions and expr
- scope creation
- local scope creation
- adding error messages
- adding expr
- adding parans to expr
- supporting other keywords (while , if)
- bytecode runner
- JuaLang Extensions def in bytecode runner
- code optimization
- standard library
- preprocessors
- error JuaVoidType impl
