Jump to content
  • Advertisement
Sign in to follow this  
Zotoaster

Unity C&C on my programming language

This topic is 2471 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey all,

Not been on GameDev for a while now, but assuming it still retains the professional demeanour it had when I was around, I think this is the right place to post this.

I may get a bit of flak for this. I understand making a programming language seems like a bit of a pointless task considering how many there are out there and how unlikely mine is to compare to any of them, but truthfully, I'm fascinated by the internals of languages and for a few years now I've dreamed of being able to write and execute code in my own programming language (I think all programmers have had this urge at one point or another).

So I've reached a few milestones both in my understanding of programming languages and in development, and after a few years and countless rewrites, I've finally made something that's almost ready for beta testing, though not quite yet. What I'm looking for is a critique of what I've currently got, what features should be added, what should look or behave differently, and whether any of you think this is even worth my time at all :) The plan is to integrate this into a larger project that I plan on making - a game editor sort of like flash but in 3D, where every object has a class and is accessible and modifiable from within the editor. Some kind of sandbox basically.


So! With all that aside, here's a brief rundown on my language.

It's a C-style syntax language sort of modelled on Java. It's object-oriented, statically typed (with type inference) and compile-time linking, forward-referencing, supports polymorphism through inheritance and virtual methods, interfaces (much like Java's), and runs on a VM with no dynamic lookups EVER unless it's a call to an interface method (in which case the method is looked up at runtime by it's signature, and once that's done it's cached in the instructions so it doesn't have to do that lookup again). At the moment it has a very simple garbage collector (plain old mark and sweep), though I threw in an extra generation for older objects because it was pretty easy and gave me that little more efficiency. I had planned on making an incremental collector but this is a pretty big task and I wanted to make progress in other areas, so for this version this will do.

So basically like Java, right? Well I wanted to make this a little easier and less verbose. Arrays are created much like in Java (new int[] for example), but they are all dynamic and can change size, so everything is consistent. Strings are treated as primitive types by the compiler (almost) so to the user, using strings feels like using any other primitive type (though in the VM they are proper objects). Creating variables is much quicker and intuitive, as the type of the variable is set when the variable is assigned to. For example, var a = 3; will make 'a' an int, whereas var a = new Foo will obviously make it a Foo reference. For variables that you want to assign to later, you can qualify them using a colon, example, var me:Person;.

Functions and methods are similar (yes, you can have functions outside of classes). Here's a basic function signature: function myFunc(int a, int b):string. Notice the return type is put at the end, after a colon. If you don't put a return type, the default is 'void'. Virtual methods are exactly the same, except they use the 'virtual' keyword rather than 'function', example, virtual Quack(). The same goes for override methods and the 'override' keyword.

All members are public by default. Being quite lazy I managed to work myself into a situation where making private and protected members using standard syntax was very hard to do, so in the meantime, any member with an underscore in front (example, _hello) will be made protected.

Finally, one can bind functions and methods in the language to C++ so execution is much faster. Currently the system is a bit confusing (the C++ side anyway) and only I'm using it, however, linking in the scripts is easy: function myFunc(int a, float b) = MyFunc; (where 'MyFunc' is defined in C++ to point to a callback). If I take this further I'm going to make it so you can import a DLL in a script and link to it in the same way.


So that's a brief rundown on my language. If you want to see how it looks, here's a not-very-serious program I made with it earlier just to test it's features and try to squeeze as many bugs out as I could. It's a very simple shell system where the user types commands, the base Shell class creates a Scanner object to tokenize the input, and then the command and arguments are handed to a virtual 'RunCommand' method, which can be overridden in derived classes for extra functionality. See if you can follow how the code is executed.


package shell
{
/** Scanner */
class Scanner
{
var _str:string;
var _cur:int;

Scanner(string str)
{
_str = str;
_cur = 0;
}

function HasNext():bool
{
return _cur < _str.length();
}

function GetNext():string
{
var out = "";
while (_cur < _str.length())
{
if (_str[_cur] == ' ')
{
_cur++;
break;
}

out += _str[_cur];
_cur++;
}

return out;
}
}


/** Core shell */
class Shell
{
var _run:bool;

Shell()
{
this._Intro();
_run = true;
}

virtual RunCommand(string com, string[] args):bool
{
if (com == "exit")
{
_run = false;
print "Goodbye!";
}
else if (com == "help")
this.Help();
else if (com == "play")
{
var ms = new MovShell();
ms.Start();
}
else
return false;

return true;
}

function Help()
{
print "Valid commands:";

var cl = this._ComList();
foreach (c in cl)
print " - " + c;
}

virtual _ComList():string[]
{
return new string[]
{
"exit",
"help",
"play"
};
}

virtual _Intro()
{
print "Welcome to the shell";
}

function Start()
{
while (_run)
{
var sc = new Scanner(input(">> "));

var com = sc.GetNext();
var args = new string[];

while (sc.HasNext())
args.add(sc.GetNext());

if (!this.RunCommand(com, args))
print "Unrecognised command: " + com;

print "";
}
}

}


/** Movement shell */
class MovShell : Shell
{
var _x, _y:int; // Positions

MovShell()
{
_x = 0;
_y = 0;
}

function Move(int x, int y)
{
_x += x;
_y += y;

print "Position: [" + _x + ", " + _y + "]";
}

override _ComList():string[]
{
var cl = base._ComList();
cl.add(
"up",
"down",
"left",
"right",
"move"
);

return cl;
}

override _Intro()
{
print "Welcome to the game";
}

override RunCommand(string com, string[] args):bool
{
if (!base.RunCommand(com, args))
{
if (com == "up") this.Move(0, 1);
else if (com == "down") this.Move(0, -1);
else if (com == "left") this.Move(-1, 0);
else if (com == "right") this.Move(1, 0);
else if (com == "move")
this.Move(args[0].toInt(), args[1].toInt());
else
return false;
}

return true;
}
}

}
using shell;

// Main entry point
function main(string[] args)
{
var sh = new Shell();
sh.Start();
}



So that's what I've got. Tell me what you think, I want feedback from the community so I can see if I can make anything that anyone would ever want to use!

Share this post


Link to post
Share on other sites
Advertisement

It's a C-style syntax language sort of modelled on Java.


So C# you mean?

I think there is plenty of value in the exercise, but a few syntactic changes aren't enough to get me excited; let alone use this over existing mainstream languages.

Share this post


Link to post
Share on other sites
It seems like a good start. Do you have exceptions or are you relying on return codes for the time being? Are your "built in" strings immutable like Java's? It looks like array.add() is var args? Do you have a universal base class?

The nice syntax is great, but like Telastyn it wouldn't be enough to entice me. That said, you have a good base now from which you could start including some more significant language features - the kind of things that could start making productivity differences. Any thoughts on where you want it to go?

  • Closures
  • Templates or Generics
  • Value types
  • References
  • RAII
  • Immutable types
  • ...

Share this post


Link to post
Share on other sites
Thanks for the feedback. I realise right now there isn't much to it to persuade anyone to move to it, though as you pointed out, once I've got the bare-bones done and simple programs can be written, it's time to start having some fun.

On to your questions, rip-off;

Right now I don't have exceptions. I'm not to sure how to handle catching various types at the bytecode level, since bytecodes don't use types. I might look into it a bit further though, because it would be nice to have. Strings are immutable. array.add() is var args. All the other methods are just one (or two) args: push, pop, enqueue, dequeue, insert, remove. More string and array methods to come. There is a universal base class, called Object (might as well make it familiar). Primitive types aren't derived from it, but also neither are string and array, even though in the VM they are in fact objects. This shouldn't be a problem once I implement autoboxing (may have to also implement templates/generics to box arrays).

I haven't used closures much so I'm not very sure how they work, so I wouldn't like to go about implementing them. Value types are in the todo list right now. I think I'll make simple C-style structs. Trying to blend them in with classes can get messy. I won't be making references outright but I might allow passing by reference to functions. Not true RAII but there is a virtual Finalise() method in Object than can be overridden and is called when the garbage collector reclaims the objects. This may be a while after all it's references are lost though so I might implement come kind of Dispose pattern thing. Only immutable types in the pipeline now are enums, and to be honest it will probably stay that way.

Obviously the better abstractions you can make in a language the better your code can be, but I'm not dead set on making this a totally GP language, rather, I want to aim it towards games and interactivity. Some more ideas I'd like to borrow from UnrealScript are states and time-based code (though these are kinda urscript's defining features).

There are some useful data structures and design patterns that I would like to integrate directly into the language to promote their use. For example, trees are a remarkably good way to organise data. Maybe trees could look like this:



// GUI Gadget
class Gadget [ITreeNode] // 'implements' ITreeNode
{
virtual Update()
{
// ...
}
}


function main(string[] args)
{

var gui = new Window("wnd1"):[ // Create tree using nested syntax
new Frame():[
new RadioButton("red pill"),
new RadioButton("blue pill")
],

new Button("OK")
];

// Assume ITreeNode is iterable
foreach (n in gui)
if (n is Gadget) // Without templates, all children would have to be type ITreeNode - unless I just force the compiler to do otherwise in this case
// Edit: No, in fact, if it's an interface, the implementation is up to the user. Maybe even getters and setters can be optional.
n.Update();
}



Events and event listeners would be nice too, though it's easily done in the standard library.

Any other ideas?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!