As a follow-up from a school assignment (where I had to build a full parser for a very simple language) I decided to construct a language of my own, just for fun.
Orignally, I was a C programmer, my part-time job entails PHP, and I have a fondness for languages like Scheme, Lua and Javascript. Drawing inspiration from all these language, I have (for now) decided on a syntax like this;
Variables
int x = 42;
dynamic j = 'x';
y = 'x';
j and y are both of the same type, ‘dynamic‘, in the case of y, this is implied. Dynamic variables can contain any type of content, others are type strict.
Built-in types
int x = 42;
float j = 4.5;
string s = "hello world";
array l = (1, 2, 3, 4, 'a', 'b', 'c', 'd');
map m = [a: 1, b: 2, c: 3, d: 4];
code c = { a = 5; a++; doSomething(a); };
function f = function() {};
class c = class [];
Statements are first class citizens of the language, albeit not for the right reasons yet.
Functions
string s = "Amount ";
f = function(int x, function y, z) uses (s) {
x += y(z);
return s ~ x;
}
This here example shows literal strings as a language construct, and first class citizenship of functions. All functions are closures, but require (like in PHP) the desired variables in the closure to be explicitly summed up. String concatenation is done through the ‘~‘ operator.
Classes
surface = class [
private x : 0,
private int y,
public constructor makeNew : function {
this->x = 5;
this->y = 7;
},
]
Classes, in my opinion, are more like hash-tables than functions, as such, the syntax reflects this. ‘constructor‘ is a special keyword that indicates that the method defined is the constructor of said object. As shown, the name of this method can be anything. I haven’t quite decided on overloading and it’s implications, so I’ve left it at that. As with functions, classes are first class citizens of the language. That means they can be assigned to variables, copied and have operations performed on them. An example:
// Class with two attributes, implied public, of undefined type
a = class [ x, y ];
// 'b' is an empty class that extends 'a'
b = class [] extends a;
c = interface [ public int x, public function getName ];
d = class []; // 'd' is an empty class
d implements c; // which now implements 'c'
Operators like ‘extends‘ and ‘implements‘ can be applied to a class during it’s entire lifetime. Instances of those classes made before the operations do not change with them.
/* Classes can be extended with anonymous classes,
* same for interfaces.
* Not really useful, but syntactically it's valid
* sidenote: newlines are regarded as whitespace */
a = class [ x, y ] extends class [
function getName() { return 'name'; }, int c ]
implements interface [ function getType ];
x = class [ function getThing(a, b) { return a + b; } ];
a has x; // 'a' now has a method 'getThing'
b extends a; // but 'b' does not.
A trick I picked up from Perl 6, class-traits. I believe this will be very beneficial in bridging traditional classes and prototype-based languages by allowing class extending without adding to the inheritance chain.
Operators
/* All common symbolic operators (+, -, &&, extends) have
* function-like counterparts. Internally, the symbolic ops
* are just syntactic sugar for the function-like ops */
print(2 + 2);
print(add(2, 2));
print(true && false);
print(and(true, false));
// Variable amount of parameters when it makes sense
print(and(true, true, true, true, true, true, false));
print(subtract(40, 3, 4, 6, 2, 13));
But also
/* Symbol quoting stolen from Lisp,
* symbols a, b and c are not evaluated */
function a = _function(('a, 'b, 'c), (x, y, z), {
return add(a, b, c) * subtract(x, y, z); });
Which, as you can see is exceedingly ugly. Neither concise nor elegant, the syntax has grown to represent what I want to avoid in general. This either means I will need to get a clue as to resolving this syntactically, or I will have to remove the operators-as-functions feature from the language, but I haven’t decided. The entire concept of code as a first class citizen of the language (like in Smalltalk) was created out of necessity to make this work.
Conclusion (for now, anyway)
Although I have started with a parser for the basic language, stuff like the operators-as-functions and first class citizenship of codeblocks need to be resolved to add to the whole of the language instead of looking like I just clobbered it all together. Also, I still need to name it… ‘project cwx’ sounds increasingly cheezy.