Introduction
Ankoku is a lightweight embeddable scripting language written in Rust.
The main inspirations are JavaScript, Rust, and Java-style OOP.
If you know JavaScript, Ankoku should be easy to pick up.
Features
- Cool name
- Not Lua
Examples
Here are some basic examples to demonstrate the syntax and semantics.
Hello World
print("Hello, world!");
Recursive Fibonacci
fn fib(n) {
if (n < 2) { n } else { fib(n - 1) + fib(n - 2) }
}
print("Hello, world!");
First Class Functions
fn do_10_times(f) {
for i in 0..10 {
f(i);
}
}
do_10_times(fn(i) {
print(i)
});
Objects
let object = {
just_a: "A hashmap, dictionary, hash table, etc."
};
print(object.a_thing);
Classes
For more about OOP, read Object Oriented Programming in Ankoku.
class Animal {
fn make_sound() {
print("*crickets*");
}
}
class Cow: Animal {
fn make_sound() {
if (this.loud) {
print("MOOOO!!");
} else {
print("Mooo");
}
}
}
let cow = Cow.new();
cow.make_sound(); // Mooo
let animal = Animal.new();
Animal.make_sound(); // Animals.
Object Oriented Programming in Ankoku
OOP is implemented into Ankoku, in a mix of prototypal and traditional styles, with the goals of being fast without too much magic. When defining a class, you define all the methods like this:
class Animal {
fn make_sound() {
print("*crickets*");
}
}
class Cow: Animal {
fn make_sound() {
if (this.loud) {
print("MOOOO!!");
} else {
print("Mooo");
}
}
}
but they actually desugar into normal functions:
fn Animal.make_sound(this) {
print("*crickets*");
}
fn Cow.make_sound(this) {
if (this.loud) {
print("MOOOO!!");
} else {
print("Mooo");
}
}
(this
is prepended as the first argument unless the function is a static fn
)
And then it also creates constructor functions and a type:
type Animal(Object);
fn Animal.new() {
// user code goes here...
Object.new(Animal) // create a new object of type Animal
}
type Cow(Animal);
fn Cow.new() {
Object.new(Cow) // create a new object of type Cow
}
Object is at the top of the inheritance hierarchy and includes static methods to create new objects.
Anyways, each object has a type:
let object = {}; // empty object, desugars to Object.new(Object)
print(object is Object); // true
let animal = Object.new(Animal); // animal
print(animal is Animal); // true
The type is accessible by calling typeof
:
let object = {}; // empty object
print(typeof(object) == Object); // true
print(typeof(object) == Animal); // false
let animal = Object.new(Animal); // animal
print(typeof(object) == Animal); // true
print(typeof(animal) == Object); // false
However, typeof
only gives the direct type, so use is
for comparisons to allow inherited types.
Anyways, Object.new(type)
will set properties on the object to the associated non-static functions (fn Animal.*
):
let animal = Object.new(Animal); // finds all functions for animal (Animal.*)
print(animal.make_sound); // [function]
print(animal); // { make_sound: [function] }
But it will set it to bound versions of them (using .bind
on Function), so the first parameter (this
) is set to the created object.
type Example(Object);
fn Example.assoc_types(this) {
return this;
}
let example = Object.new(Example);
print(example.assoc_types() == example); // true
And you can call associated functions yourself as well, if you'd like to use a specific version:
let cow = Cow.new();
Animal.make_sound(cow); // prints "*crickets*"
This is a reasonably elegant system that is sort of confusing, but combines some of the dynamicity of prototypes with the rigidity of OOP.
Reference
This is an API reference for the built in types.
Function
Functions are instances of the Function class, which is an FFI class and private. They expose a few methods, generally for making more functions.
Function.call(this, arguments)
Call this function with the specified arguments.
Implemented in the VM.
Function.bind(this, ...arguments)
Bind this function with a starting number of parameters. Most commonly used to bind this
in Object.new
.
Example implementation:
fn Function.bind(this, ...arguments) {
return fn(...args) {
return this.call(arguments.concat(args));
}
}
Object
Object is the root class of the hierarchy. Everything is Object
.
Object.new(type)
Creates an instance of a Type.
Type
Type is the type that specifies types. It's implemented in the VM, but is still totally meta.
type name(parent);
Not a function, but built in syntax. Creates type name
that inherits from parent
.
Example
type Cat(Object);