I wrote a full-fledged programming language in GDScript!

In this thread I would like to share my interesting and unique project called DinoSource!

DinoSource is a full-fledged interpreted programming language written in pure GDScript. I tried to adhere to the standard practice of designing programming languages ​​using the PreprocessorLexerParserInterpreter step-by-step process, which allows for quick changes.

Currently, the language supports everything you need: variables, arrays, constants, enums,2 types of comments, functions, conditions, four types of loops, switch statements, arephrasing, library header inclusion, and error checking. You can find a list of the language’s capabilities at the bottom of the thread.

I’m currently working on classes/objects, after which I’ll release DinoSource open source on GitHub. In the future, I plan to add a plugin for easy and quick development of your own programming language, any type, and any syntax, based on DinoSource.

Example and capabilities of the language:

/*

        DinoSource Test Code

*/

include LIB/TestLib

const int PI = 3;
//PI = 5; // ERROR
int i; //While Index. default 0
bool run = !false; // !false = true
var arr = [“One”,2,3,4,5,6,8 - 1,false,9,“10!”];
var double_arr = [ [13,8,64] [true,false] ];
string text = "Hello " + str(2020+6) + “!”;
var any_type = “DinoSource”; // var = string, bool, int or array

enum Mode
{
Play, // 0
Pause, // 1
Resume = 8,
Stop = 64
}

print("Enum Pause is: "+str(Mode.Pause));
print("double_arr[0] = "+str(double_arr[0]));
print("double_arr[1] = "+str(double_arr[1]));
print("double_arr[0][2] = " + str(double_arr[0][2]) ); //64

int plus (int a,int b)
{
int ret = a + b;
print(str(a)+" + “+str(b)+” = "+str(ret));
return ret;
}
int ret_func = plus(1,2);

string operation_func (int mode,int a,int b)
{
if (mode==0)
{
return “POW Mode: “+str(a)+”“+str(b)+” = "+str(ab);
}
else if (mode==1)
{
return “DIV Mode: “+str(a)+”/”+str(b)+” = "+str(a/b);
}
else
{
return “Other”;
}
}
print(operation_func(1,4,2));

void _PRINT(string t1, string t2)
{
print(str(t1)+" "+str(t2));
}

_PRINT("Hello ",“DinoSource!”);

var not_typed_func (var any_type)
{
if (type(any_type)==“int”) {return 101;}
else if (type(any_type)==“bool”) {return false;}
else if (type(any_type)==“string”) {return “This string!”;}
else {return 0;}
}
var _type = not_typed_func(“Hi!” /* int, string or bool type support*/ );
print("not_typed_func return: “+str(_type)+” | Type Var: "+type(_type));

while (run && i<4)
{
print("While: "+str(i));
i+=1;
}
if (!run) {print(“While not work!.”);}

for(int i = 0; i < 1000; i++)
{
if (i==10) {break;} // End FOR
else if (i==4)
{
print(“SKIP “+str(i) +” IN FOR”);
continue;
}
else if (i==8) {print("FOR is "+str(i))}

print("FOR: "+str(i));
print("Array["+str(i)+"] = "+str( arr[i] ));

}

int num_call = 3;
repeat (num_call) // Repeat block 3
{
print(“Repeat BLOCK”);
int _not_global_var = 4;
_not_global_var += ((4/2) - 1) * 3; // = 7
_not_global_var–; // = 6
print(_not_global_var);
}

delete num_call; // DELETE VAR

int JMP_cnt = 4;
POINT my_point; // ← Save point
JMP_cnt–;
if (JMP_cnt > 0)
{
print("JUMP - "+str(JMP_cnt));
if (JMP_cnt==2) {print(“JMP_cnt is 2!”);}
JMP my_point; // Jump on point
}
print(“END JUMP.”);

bool bl1 = false;
bool bl2 = true;
bool bl3 = true;

if ((bl1 == true || bl2 == true) && bl3 and true) // ||/or, &&/and
{
print(“UNLOCK!”);
}

int sw = 3;
switch (sw)
{
case 1: print(“CASE ONE”); break;
case 2,3: print(“CASE TWO OR THREE”); break;
default: print(“CASE OTHER”); break;
}

Output:
[“Enum Pause is: 1”]
[“double_arr[0] = [13.0, 8.0, 64.0]”]
[“double_arr[1] = [true, false]”]
[“double_arr[0][2] = 64.0”]
[“1.0 + 2.0 = 3.0”]
[“DIV Mode: 4.0/2.0 = 2.0”]
[“Hello DinoSource!”]
[“not_typed_func return: This string! | Type Var: string”]
[“While: 0.0”]
[“While: 1.0”]
[“While: 2.0”]
[“While: 3.0”]
[“FOR: 0.0”]
[“Array[0.0] = One”]
[“FOR: 1.0”]
[“Array[1.0] = 2.0”]
[“FOR: 2.0”]
[“Array[2.0] = 3.0”]
[“FOR: 3.0”]
[“Array[3.0] = 4.0”]
[“SKIP 4.0 IN FOR”]
[“FOR: 5.0”]
[“Array[5.0] = 6.0”]
[“FOR: 6.0”]
[“Array[6.0] = 7.0”]
[“FOR: 7.0”]
[“Array[7.0] = false”]
[“FOR is 8.0”]
[“FOR: 8.0”]
[“Array[8.0] = 9.0”]
[“FOR: 9.0”]
[“Array[9.0] = 10!”]
[“Repeat BLOCK”]
[6.0]
[“Repeat BLOCK”]
[6.0]
[“Repeat BLOCK”]
[6.0]
[“JUMP - 3.0”]
[“JUMP - 2.0”]
[“JMP_cnt is 2!”]
[“JUMP - 1.0”]
[“END JUMP.”]
[“CASE TWO OR THREE”]

Possible incorrect grammar, sorry my native language is not English.

I would be glad if you shared your thoughts on this, as well as your wishes!

6 Likes

As someone who recently made a compiler this stuff is insane lol. Anyone making any language is insane but doing any of that stuff in a high level language like gdacript is mad respectable!

1 Like

I’ve been hesitant to comment on this, but while I think this impressive, I also have to ask why?

I’m just pretty confused.

I really don’t see any practical purpose for creating a new programming language, especially in GDscript of all places.

Is there something I’m not seeing here?

2 Likes

Is there a reason to: no, gdacript is a high level language. High level languages aren’t built for these kinds of uses.

Why make it then: It’s a cool proof of concept and also just a really cool flex, I personally like to set myself challenges in coding like this. It’s similar to why would you make an operating system, it with be better than windows, Linux distros, Mac etc. but it’s still a great learning experience and also just a cool flex lmao

5 Likes

Thank you, glad I could impress!

I’ve been into this kind of thing since childhood, and I tried to do it in Game Maker 7, but the capabilities of the GML language didn’t allow it, unlike GDScript.

Actually, I was making a mini programming language for my programmer simulator, and I got carried away with it :smiley:

It can be used for modding games, making large edits with it, imitating other popular languages, or used in some larger-scale projects where a built-in programming language for designing something would be useful, or used in gameplay, for which this language was originally developed.

4 Likes

That’s a pretty good use-case, actually. But for Godot specifically, I’d just stick to GDscript for modding and also use the Mono version for an optional C# option.

1 Like

I think alone people doing this. Speaking from experience making a language is one of the hardest things I have ever done in programming, I don’t know about others but that’s how I felt. And doing that in a language that was never intended for such a use case is just insanely impressive. I see the use cases but I would assume that’s not really the point (correct me if I’m wrong).

2 Likes

That’s pretty cool, but it’s not Piet.

5 Likes

I’m having trouble with loops. If I use while(true), the Godot window freezes when I launch it, but the editor and output are stable. What can help with this? Will multithreading help in this case?

Godot already runs inside a while(true) loop in essence. Doing while(true) inside that loop locks it up. Find another way to do your loop, or use the existing loop through _process() or _physics_process().

In general, while loops should always be handled that way in Godot.

1 Like

Bloody hell, I just lost an hour fawning over this marvel, and I’m not even a programmer :slight_smile:

2 Likes

At first, I thought about teaching the interpreter to split the code into two iterations, initialization and update, but that would be very specific and inconvenient.
I’ll simply add the ability to call functions from GDScript; this will give me more flexibility, like this:

DinoSource:
int _var = 12;
int update(int arg)
{
//update all process
return 0;
}

GDScript

var pars = DSParser.new(…)
var ds = DSInterpreter.new(pars)

func _ready():
ds.run() # running all the code and, accordingly, initialization

func _process():
var ret = ds.callFunc(“update”,[0]) # We call the function every frame

Edit:
Already implemented. I’ve seen something similar in LUA plugins for Godot.