Reaper

From Esolang
Jump to navigation Jump to search

Reaper is a lazy object-oriented language by Ørjan Johansen (originally idea from 2002, but not published until 2006). It is lazier than most languages, in that objects perform actions only at the last possible time, when they are destroyed. To facilitate destruction the language has a reference-counting garbage collector (the reaper), as well as replacement instructions.

Syntax

The syntax may be approximated by the following BNF description:

program ::= destructor
destructor ::= statement {statement}
statement ::= class-definition
            | class-prototype
            | expression
class-definition ::= class-declaration INDENT destructor DEDENT
class-prototype ::= class-declaration REDENT
class-declaration ::= constructor parameter-list
parameter-list ::= {variable | "(" parameter-list ")"}
expression ::= replacement
             | constructor expression-list
             | variable
replacement ::= expression ("=" | ":=") expression
expression-list ::= {expression | "(" expression-list ")"}
constructor ::= IDENTIFIER
              | NUMBER
              | STRING
variable ::= IDENTIFIER
comment ::= "--" {comment-list}
comment-list ::= "(" {ANYCHAR - ("(" | ")") | comment-list} ")"

Nested destructor blocks are indented; the tokens INDENT, DEDENT and REDENT denote a newline beginning, ending or continuing a destructor block, according to how it is indented. Note that newlines may be used freely as whitespace anywhere none of the indentation tokens can apply.

Numbers and strings follow approximate C syntax. Identifiers may contain letters, digits, periods, dashes and underscores.

Identifiers in Reaper are capitalization insensitive. There are also several ways of writing identifiers concatenating more than one word. For example:

  • The builtin constructor print may also be written as Print or even PRINT.
  • TiddlyWinks, tiddly_winks and tiddly-winks are all equivalent.
  • Capable, CAPABLE and capable are equivalent, and so are CapAble and CAP.able, but the first group is of course different from the second.
  • 3X is a shorter form of 3_x.

Statements

A class definition generates a new class with a corresponding constructor and destructor. The definition is visible in the rest of the surrounding destructor.

A class prototype only gives the constructor. It is useful for creating mutually recursive classes. It is an error for a constructor to be executed before the corresponding destructor has been defined.

An expression statement constructs an object and then promptly forgets it. Unless the object was taken from a variable it is then destroyed, since there can be no other references to it.

Expressions

A variable expression constructs a new reference to the object in the variable. If the variable has not been mentioned previously it is generated in the scope of the current destructor, as a new dummy object (with empty destructor).

A constructor or replacement expression constructs a new object of the corresponding class, constructing the arguments recursively.

Strings and numbers are also considered constructors (with no arguments), so new objects are created each time they are evaluated.

Destruction

Reference counts are kept to all objects and classes. When the reference count of an object reaches 0 (either because it was forgotten by other objects or because it was replaced by another object), its destructor is constructed from its class and the argument list of its constructor, and then run immediately.

As each statement of a destructor is executed, the references used to perform it are released, thus if a variable or object used by a statement is not referenced anywhere else, it will be destroyed.

The reference counting scheme does not detect unreachable circular references. Thus if you want to prevent a destructor from being run, you can create a circular data structure referencing its object. This will not work for a = replacement, however, in which case a := replacement may be used to explicitly cancel the destructor.

Builtin classes

  • The destructors for replacements replace all references to the first argument by the second. The deep replacement using := also replaces the destructor of the first argument, while the shallow replacement using = allows it to run.
  • The destructor for print string or number will destroy and print its argument.
  • The destructor for read_line object will read a line of input, then replace the object by the resulting string.
  • The destructor for ifEof object will destroy object if at end of file.

Example

A cat program:

Cat
    ReadLine a
    Print a
    c = Cat := NOP
    IfEOF c
    c := NOP
Cat