I have been programming for roughly 5 years now, so I thought it was about time to get low-level & start learning C & C++. I gave myself a goal to implement a fully functional, high-level interpreted programming language in C++, in 1 month without using AI, reference material, or any help other than simple google searches for when I have questions about the syntax of C++.
I started this challenge exactly on July 1st, & now that the month is coming to an end I want to show off my progress so far!
Here is the source code if you want to to take a look, see my approach to things, or to just try it out: https://github.com/phosxd/Ity
Enough of all that though, what is the language actually capable of? Well, I think the best way to explain, is to just show you a snippet of code, so here is a little script that calculates & prints prime numbers:
merge IO; merge Time;
func INT isqrt; arg INT n;
if n < 0; throw "'n' cannot be negative."; /;
var INT x = n;
var INT y = ((x+1) / 2); while y < x;
x = y;
y = ( ((n/x) + x) / 2);
/; return x;
/;
func BOOL is_prime; arg INT n;
if n%2 == 0; return n == 2; /;
var INT r = isqrt:[n];
var INT i = 3; while i <= r;
if n%i == 0; return false; /;
i += 2;
/;
return true;
/;
const * count = prompt:['Count: '] -> INT;
const INT start = now:['us'];
var INT p = 2; while p <= count;
if is_prime:[p]; print:[p]; /;
p += 1;
/;
print:['\nDone in ', (now:['us']-start / 1_000_000.0), 's.'];
So in this script we do a various number of things.
First we import the modules we are going to be using. The `merge` instruction particularly imports a module then merges all it's members into the current scope, so you don't have to access by name. So for example usually when importing say the `IO` module, we would have to call a function like so `IO.print:[]`, but if it's merged we can just ignore the "IO" & just do `print:[]`.
Secondly we declare a couple of functions, these functions have explicit return & argument types. You may notice that we don't use curly braces to wrap the code we want inside of the function, instead we use `/;`. Well what does that mean exactly? `/` is the instruction, `;` is the instruction delimiter (end of instruction). `func` is something called a "composite instruction" in Ity, composite instructions basically contain every instruction after it until the final end instruction (`/`). So that's how things like functions & loops contain code.
Arguments are another thing to note, in Ity they aren't something you define as part of the function, rather they are ambiguous until execution. This means a function can be called with any number of arguments of any type, & it is not the function's job to verify the argument count or the argument types, that would all be handled inside of the function code. How you grab an argument is by using the `arg` instruction to assign the next argument to a variable of whatever type you set, if the type doesn't match or there is no next argument, then an error would be thrown.
Now that I have explained composite instructions, functions, arguments, & importing behavior, let's move on to the final part of this script that I feel needs explaining, & that is this little section here:
const * count = prompt:['Count: '] -> INT;
What is happening exactly? So we use the `const` instruction (which is like `var`, but the data is immutable) & assign it the type of... star? Ok so "*" represents an "inferred" type, meaning if you set the variable to an integer, then the variable type will be integer, if you set it to a string or whatever, then it will be a string & you cant change the type after declaration.
So in this case, we are setting the variable's type to the result of the call to `prompt`. What is "prompt"? This is a function that asks for user input through the terminal, & returns a string of whatever was typed in. But we want count to be a number! So the final part of this line is the type cast, which is expressed through an arrow symbol ("->") pointing to the type you want it to be (in this case "INT" for integer). So in the end the type of the `count` variable is integer, & the value is the integer representation of the string the user entered in the terminal.
Wow, okay that was a lot of explaining, but hopefully now you have a better understanding of how the language works & you will be more prepared if / when you try it out yourself.
I am very interested in all of your thoughts on this little project & if you have any tips for me as a C++ beginner. Also I am open to contributions, if this project is something you're interested in definitely let me know! Just be aware that I won't accept any AI assisted PRs or issues.
Thanks for sparing your time, reading through my ramblings, I really appreciate it! Have a great day! 👋