Aardvark

From Esolang
Jump to navigation Jump to search

Aardvark is a language created by DanielDG to abuse the async/await syntax. The only datatype in Aardvark is asynchronous tasks (a.k.a. futures or promises), and the only type of control flow is async/await. Despite that, Aardvark is Turing complete.

Asynchronous functions

Asynchronous functions and async/await are very common features of modern programming languages. If you are unfamiliar with asynchronous functions, you should probably read about them in some other language, like Python, JavaScript, or C#, before learning Aardvark. But in a nutshell, asynchronous functions are pausable functions. A regular function runs until reaching a return statement and then exits. An asynchronous function can also choose to pause itself, saving its current state and returning to the caller, who can then decide whether to resume it or not.

Syntax

Aardvark's syntax is similar to C.

Functions

async functionName(param1, param2, ...) { code }

Defines an asynchronous function. Each program contains a function called main, which is its entry point.

return someValue

Returns from a function.

functionName(arg1, arg2, ...)

Calls a function. Since Aardvark's functions are asynchronous, they don't actually run when you call them. Instead, they return a task object, which you have to await in order to run.

Await operator

await someTask

Runs a task to completion and returns its result. If the awaited task pauses itself, the current task also pauses (as well as any task awaiting it). Once the current task resumes, it immediately resumes the awaited task.
If you await the same task twice, it will run only the first time and return the same result immediately the second time.

Output

print "Print with no newline."
println "Print with a newline."

Prints a string. Note that print and println have to be followed by a string literal.

Variables

variableName = value

Sets a local variable.

Comments

// This is a comment.
/* This is also a comment. */

Grammar

Here's the whole grammar of Aardvark in EBNF. In case this grammar is ambiguous, Aardvark uses a "greedy" parser.

program = ws {function ws}
function = 'async' ws ident ws '(' ws {ident ws ',' ws} [ident ws] ')' ws '{' ws {statement ws} '}'
statement = expression | ident ws '=' ws expression | 'return' ws expression | 'print' ws string | 'println' ws string
expression = ident | '(' ws expression ws ')' | 'await' ws expression | ident ws '(' ws {expression ws ',' ws} [expression ws] ')'
ident = (alphabetic_char | '_') {alphanumeric_char | '_'}
string = '"' {char_except('"', '\\') | '\\n' | '\\"' | '\\\\' } '"'
ws = {whitespace_char | newline | '//' {char} newline | '/*' {char} '*/'}

Builtin Functions

Aardvark has four builtin functions. Like all other functions, they are asynchronous, so you have to use the await operator to run them. The following list describes what they do when awaited.

void()

Does nothing and returns another void() task. void() is also what functions with no return statement return.

ready(task, default)

Checks if task has already completed. If it has, returns its result; otherwise, returns default.

poll(task, default)

A more powerful version of ready(). If task has already completed, returns its result; otherwise, tries to run it. If task returns, poll() returns its result; if task pauses, poll() doesn't try to run it further and returns default instead.

yield()

Pauses once, and then (when resumed) returns void(). Because of how the await operator works, any function that awaits yield() pauses, too. Currently, this is the only way to pause a function.

Examples

Hello, World!

async main() {
    println "Hello, World!"
}

Infinite loop

async main() {
    await main()
}

Infinite triangle

// Prints a line of asterisks.
// Accepts an asterisk-printing task: either line() or void() (which prints 0 asterisks).
// Prints as many asterisks as that task, plus one.
// Returns a copy of itself.
async line(ln) {
    print "*"
    return line(await ln)
}

// Prints an infinite triangle, given a task that prints the first line.
async triangle(ln) {
    await ln
    println ""
    await triangle(line(await ln))
}

// Prints an infinite triangle.
async main() {
    await triangle(line(void()))
}

Outputs:

*
**
***
****
*****
(...)

Computational class

Aardvark is Turing-complete since it can simulate Rule 124 (Rule 110 backward), which is known to be Turing-complete.

External resources