# Language Reference

# S2 Language Overview

The S2 language is an object-oriented and statically-typed language with syntax mostly borrowed from Perl, but with some borrowings from other languages including Java and Python.

This language is domain-specific, which means that it has a reduced feature set compared to general-purpose programming languages you may be familiar with. In particular, the flow control constructs available are restricted to conditional branching (if statements) and iteration over finite lists (foreach loops).

The language has several features which are designed to make life easier:

- Variables can be referenced from within string literals, in which case their values will be interpolated into the resulting string. This behavior is similar to perl.

- String literals can be given enclosed in three sets of quotes (`"""`), which allows quote characters to be included within the string unescaped. This is useful for producing HTML which features lots of quote symbols.

- String expressions can be used as statements, causing their value to be implicitly output to the client.

- Properties can be defined which are special global variables exposed from a layer to be set from other layers or from a friendly customization interface.

This section serves as a reference guide for the S2 language. Anyone who is familiar with procedural programming should be right at home. If you have not done programming before, you may like to get an idea of the concepts behind programming before you begin.

# Literals

S2 supports integer, string, boolean, array and hash literals:

`123`

  Integer literal representing the number one hundred and twenty three.

`"Blah blah blah"`

  Simple string literal. Variables are interpolated and escape sequences are processed.

`"""string with "quotes" in it"""`

  Triple-quote string literal. Quotes can occur within with no escaping for one or two consecutive characters. Variables are interpolated and escape sequences are processed.

`true`
`false`

  The two boolean literals.

`[ item, item, item, item ]`

  Array literal. All items must be of the same type, and this literal will return an array of that type. Trailing commas are fine, if you want to include them.

`{ key => value, key => value, key => value }`

  Array literal. All key items must be strings, and all value items must be of the same type. This literal will return a hash of that type.

The following escape sequences are supported in strings:

`\n`

  Newline

`\"`

  Literal quote

`\\`

  Literal backslash

`\$`

  Literal dollarsign

# Variables

S2 supports several primitive types, as well as regular and associative arrays and objects based on classes.

## Variable Types

S2 has the following primitive types:

`int`

  An integer

`bool`

  A boolean (true/false) value

`string`

  A string

## Declaration

`var int somenumber;`

  Declare a simple variable named somenumber as an integer.

`var string[] names`

  Declare a regular array of strings called names.

`var bool{} has_stuff`

  Declare an associative array of boolean values called has_stuff.

`var SomeClass[] stuffs`

  Declare a regular array of the class SomeClass and name it stuffs.

`var SomeClass{} stuffs`

  Declare an associative array of the class SomeClass and name it stuffs.

## Access

`$variable`

  Returns the value stored in the variable, or reference to the regular or associative array or instance of a class with this name.

`$this`

  An instance of the class the currently-executing function was envoked from.

`$.member`
`$this.member`

  Equivalent ways to return the value stored in this member of the class which owns the function being executed.

`$var.member`

  Returns the value stored in this member of the instance of a class known as `var`.

`$*propertyname`

  Returns the value of the property specified.

`$variable[2]`

  Returns the value stored in element 2 (3rd element) of the regular array.

`$variable{"fred"}`

  A value stored in the associative array.

# Operators

S2 operators have the following associativity and precedence, listed from highest precedence to lowest.

left | Terms (literals, expressions in parentheses, variables, function/method calls, named unary operators)
nonassoc | ++ --
left | instanceof isa as
right | not -
left | * / %
left | + -
nonassoc | < > <= >=
nonassoc | == !=
left | and
left | or
nonassoc | ..
nonassoc | ? :
right | =

## Arithmetic Operators

The S2 language has the usual set of arithmetic operators you'd expect to find in a programming language. These are the same as the arithmetic operators in perl.

As you might expect, these operators can only be applied to integers, and will return integers.

`+` | binary | Addition
`-` | binary | Subtraction
`*` | binary | Multiplication
`/` | binary | Division
`%` | binary | Modulus (remainder)
`++` | unary | Increment in-place
`--` | unary | Decrement in-place
`-` | unary | Negation

## Comparison Operators

These operators allow you to compare one value to another. Both operands must be of the same type, and all but simple equality/inequality can only be applied to integers. Only primitive types may be compared with these operators. All comparison operators return a boolean value.

`==` | binary | Equals
`!=` | binary | Does not equal
`<` | binary | Less than
`>` | binary | Greater than
`<=` | binary | Less than or equal to
`>=` | binary | Greater than or equal to

## Logical Operators

These operators perform logical operations on boolean values. All operands must be boolean, and a boolean value results.

`and` | binary | Logical AND
`or` | binary | Logical OR
`not` | unary | Logical complement

In summary, AND returns true if and only if both of its operands are true. OR returns true if one or both of its operands are true. NOT returns true if its operand is false, and false otherwise.

The two binary logical operators are usually used in an `if` statement to include two or more comparisons.

## Type Conversion/Testing Operators

These functions operate on object values only. Their left operand is the subject, while the right operand is a class name.

`isa` | Returns true if the object can be typecasted to the given class
`instanceof` | Returns true if the type of the object is exactly the classname given.
`as` | Cast the given value to the classname given, but only if the object's runtime type is compatible. If not, returns a null object.

The S2 language uses dynamic binding, which means that an object's type may be a subclass of the class of the variable which holds it. These functions allow the programmer to test the runtime type and, assuming the runtime type is compatible, convert (or cast) to a different variable type.

When calling methods on an object, it is the type of the object which determines which function will be called, not the type of the variable on which the arrow operator is applied.

## Other Operators

These operators don't really fit into a category of their own, and have perhaps non-obvious functions.

### The assignment operator: `=`

The assignment operator (which should not be confused with the equality test operator, `==`), is used to assign a value to a named variable. This means that unlike most other operators, its left operand must be a variable name. No other kind of expression will do.

The assignment operator can take operands of any type, but the right-hand operand must be of the same type as the variable given on the left, or coercable into that type.

The assignment operator also returns whatever value it has just assigned to the variable, meaning that you can chain several assignments together as follows:

    $foo = $bar = $baz = 2;

In this case, `$foo`, `$bar` and `$baz` will all be assigned the value 2.

As a special case, assignment can also be used when declaring local variables:

    var string $name = "John";

However, this is only true for local variables. Class variables cannot be initialized in this way.

The symbol `=` is used for several other assignment-like things in the S2 language, including setting property values and layerinfo. These aren't really assignment, but act similarly and in the case of property setting follow many of the rules described above.

### String Concatenation with `+`

The `+` symbol actually has two purposes in the S2 language. When one of its operands is a string, it becomes the string concatenation operator. In this form, it will firstly attempt to coerce any non-string operand into a string, then stick the two strings together to form a resulting string which is returned.

The simplest form of string concatenation involves two strings. In this case, both strings are just concatenated and that is it. However, as long as one operand remains a string, the other operand can be an integer, a boolean or an object with certain conditions. Objects may only be concatenated to strings if their class has an `as_string()` method which returns a string. The return value of this method will be used as the string value for concatenation.

String literals with interpolated variables are really just concatenation with a more convenient syntax, which is why you are able to interpolate integers and certain objects directly into string literals.

### The ternary conditional operator `? :`

This is the only operator in the S2 language with three operands. Its function can be thought of as being like an `if` statement in the form of an operator.

This operator is best explained with an example:

    $label = ($c == 1 ? "1 comment" : "$c comments");

In this example, the conditional operator and its operands are enclosed in parenthesis for clarity. These are optional, but can make things more readable. The first operand, preceding the question-mark symbol, is a boolean expression. In this case it is an equality test. If this expression evaluates to true, the second operand, which is after the question-mark and before the colon, is returned. If the expression is false, the third operand is returned.

The first operand must be a boolean expression. The second and third operands can be of any type but their types must match. The return type of this operator is the same as that of the second and third operand. In the above example, then, the return type would be string.

In all cases an `if` construct can be used in place of this operator, but the conditional operator is shorter and more readable in some cases.

### The range operator `..`

This rather quirky operator is borrowed from Perl. It takes two integer operands and returns an array of integers containing all integers between the first and second operand, inclusive. For example:

    var int[] list = 1 .. 10;

The array `$list` will now contain ten elements, each numbered in order from 1 to 10. This has the same effect as:

    var int[] list = [1,2,3,4,5,6,7,8,9,10];

This operator is really only useful for creating a loop which will iterate a certain number of times:

    foreach var int i (1 .. 10) { println "Iteration number $i"; }

This example will print ten lines, each containing a number from 1 to 10 in order.

Some readers will probably balk at the use of an array of integers to create a loop such as this, as it would use more memory than a conventional `for` loop from a general programming language.

However, you don't have to worry. The above idiom is optimised to an efficient form at compile time, so there is no memory wasted.

## Named Unary Operators

The following are the built-in named operators. You do not have to wrap the following term in parentheses.

`isnull` `$object`

  returns a boolean: true if `$object` is null (has no value)

`defined` `$object`

  opposite of `isnull`. might be prettier than negating `isnull`

`new` `ClassName`

  returns an instance of `ClassName` with all members empty or zero

`null` `ClassName`

  returns an undefined value of type `ClassName`

`reverse` `$string`

  returns copy of `$string` with characters reversed

`reverse` `$array`

  returns shallow copy of `$array` with elements reversed.

`size` `$string`

  returns number of bytes in `$string`. This behavior is deprecated. Please see note below.

`size` `$array`

  returns number of elements in `$array`

The use of the `size` operator on strings is deprecated and will be removed or updated without notice. Instead, you should use the string class's length method to get the number of characters. Remember that some characters are represented by more than one byte.

# Statements

A statement is an expression terminated by a semicolon. Statements can contain `code blocks` delimited by curly braces which can then contain one or more statements themselves. Flow control constructs can also be statements.

A statement consisting wholly of a string literal, or a string literal with other strings concatenated to it will be output to the client. A statement consisting wholly of a variable will behave similarly.

The `print` instruction will cause the string or numeric expression supplied as its parameter to be output to the client. The `print safe` alternative does similarly, but forces the output to be checked for safety. In the case of LiveJournal and FotoBilder, this means running a HTML cleaner. All untrusted (non-system) layers always run through the checker, reglardless of which print instuction is used.

## Flow Control

A limited subset of the flow control constructs normally present in high-level programming languages is available in S2. Each includes at least one code block enclosed in curly braces.

`if ( expr ) block`

  Simple conditional. If `expr` evaluates to true, `block` will be executed, otherwise it will be skipped.

`if ( expr ) block1 else block2`

  If `expr` evaluates to true, `block1` will be executed, otherwise `block2` will be executed.

`if ( expr1 ) block1 elseif ( expr2 ) block2 else block3`

  If `expr` evaluates to true, `block1` will be executed. Otherwise, `expr2` will be tested and if it evaluates to true, `block2` will be executed. If both `expr1` and `expr2` evaluate to false, `block3` is executed.

`foreach var ( expr ) block`

  `block` will be executed once for each element in the regular or associative array given in `expr`. On each iteration, an element of the array (or key of an associative array element) will be placed into the variable declared in `var`. `foreach` can also be used on strings, in which case the iteration variable must be a string and this variable will contain a character from the string with each iteration.

# Classes

Base classes are defined using the following syntax:

    class Image {
        var string url;
        var int w;
        var int h;
        var string alt;
        var string extrahtml;
        var string title;
        var string longdesc;
        function output;
        }

A subclass of any class can be created as follows:

    class Button extends Image {
        var string linkurl;
        var int bordersize;
        }

All members of `Image` are now valid in `Button`, with the addition of our two new members `linkurl` and `bordersize`. The function `Button::output` will override `Image::output` if it exists, otherwise `Image::output` will be used as a fallback.

See the variable and function reference for the syntax for accessing members of classes.

# Functions

Functions in S2 can be simple functions, methods of a class, or call functions written in the backend language from the `builtin` layer.

Functions can return data in any simple internal datatype, or void if no return data is required.

## Declaration

Declaring a function within a class is done as follows:

    class SomeClass { function do_stuff(int para1, string para2) : string;
        }

This declares a function called `do_stuff` in the `SomeClass` class with two parameters and which returns a string. The colon and type keyword may be omitted where a function will return void (no value).

Functions outside classes are declared in the same way:

    function do_global_stuff(int para1, string para2);

Functions outside classes do not need to be declared, but if they are not declared they must be defined before they are called.

Built-in functions can be declared in the core layer using the `builtin` keyword in the function prototype:

    function builtin ehtml(string s) : string; class string { function builtin ends_with (string sub) : bool;
        }

Functions can have some or no parameters, in the latter case the parentheses may be omitted in declaration. If several functions of the same name exist with different parameters, they can be defined as follows:

    function dostuff(int para1); function dostuff;

Non-class (global) functions can be implemented when they are declared:

    function do_global_stuff() { print "I'm doing stuff!";
        }

Class functions (methods) must first be declared within the class they will apply to, and can then be implemented outside the class declaration as follows:

    function SomeClass::do_stuff() { print "I'm doing stuff!";
        }

It is not permitted to implement a `builtin` function. These will instead be mapped onto some code written in the host language in the S2 backend.

Layouts are allowed to add new methods to a class without pre-declaration, but with a few special constraints. Firstly, the method must be declared and implemented before it is used. Secondly, the method name must begin with `lay_`, to avoid problems in the future when new methods may be added to the core layer with the same name.

## Calling

Functions outside classes can be called using the following syntax:

    dostuff();
    dostuff(5);

Functions in classes are envoked from an instance of the class as follows:

    $thingy->dostuff(45,"boink");

Note that the parentheses are required when envoking a function.

# `layerinfo` declarations

You can use the `layerinfo` declaration to set arbitrary meta-data for a layer. However, certain meta-data keys and values are required for each type of layer.

The syntax of `layerinfo` is:

    "layerinfo" <Text> "=" <Text> ";"
    <Text> ::= <identifier> | <string literal> | <integer
    literal>

At minimum, all that's required to create a valid layer is one layerinfo declaration with name "type", stating the type of the layer. Depending on the layer type, more declarations may be required. Valid types are those listed in the Layers section.

Example:

    layerinfo type = theme;
    layerinfo name = "Polka-dotted yellow sunrise";
    layerinfo author_name = "Jon Doe";
    layerinfo author_email = "jondoe@email.addr";
    layerinfo des = "A beautiful polka-dotted yellow sunrise with lots of yellow & orange.";
    set bgcolor = "#ffff00";
    set fgcolor = "#ffc000";

## Keys

### Required Keys

`type` | The layer type identifier.
`majorversion` | Required for core layers only.
`langcode` | Language being configured. i18n and i18nc layers only.

### Recommended Keys

`name` | The name of the layer to be displayed in the interface.

### Other Supported Keys

`des` | A longer description of the layer.
`author_name` | The name of the author.
`author_email` | The email address of the author.
`source_viewable` | Source of the layer is available to all users on the host site.
`is_public` | Allow users on the host site to use layers from other users in their styles.

The email address, if given, will likely be displayed on the host site in clear-text. You should probably leave it out if you are concerned about email-address collecting software and spam.

# Properties

Properties are single values which are exposed by the core and layout layers and set in all subsequent layers to configure aspects of a style. Properties can be of any primitive type as well as any class which provides both an `as_string()` function which returns a string representation of its data and a constructor function named after the class which accepts a `string` as a parameter and returns an object based on that string.

The purpose of properties is to expose certain configuration settings of a style such that they can be set from a friendly wizard-like interface.

## Declaration

Properties are defined using the following syntax:

    property int page_recent_items { des = "Number of journal entries to show on recent entry page";
          min = 5;
          max = 50;
    }

The key and value pairs within the braces are known as attributes. These are used by the host application for various uses, including the presentation of a friendly customization interface.

### Standard Properties

The following attributes are available for all properties:

`des`

  Required - A textual description of this property.

`values`

  A string setting the acceptable values of this property, along with a natural language description of each, in the format `"value1|Description1|value2|Description2"` and so on.

`example`

  An example of what might be put in this field. Can be used when it's not obvious what the value should look like.

`note`

  A note to be displayed with the field to enter this value.

`noui`

  Suppresses the display of this property in the editing GUI.

There are also attributes only available for specific types of property, as described in the following sections.

#### Attributes for integer properties

`max`

  The maximum value permitted.

`min`

  The minimum value permitted.

#### Attributes for string properties

`maxlength`

  The maximum amount of characters this property can contain.

`size`

  The size (in characters) of text widget which should be used to set this property from an interface.

## Setting

The `set` command is used to set the values of properties from all layers:

    set text_read_comment = "Read 1 comment";

The value set by the highest layer will be used.

## Use

In order to use a property from the core layer in a layout, you should first tell the system that you are going to use it. This makes it appear in the customization UI if applicable.

    property use property_name;

All layers can use properties as variables as described in the variables section above:

    print $*property_name;

# DocStrings

You can add short documentation strings to your classes, methods, data members and functions by placing them in quotes inside the declaration, like so:

    class Example "An example class" {
        var string some_string "An example data member";
        function some_method() : int "An example method";
    }
    function some_function() "An example global function";

These are made available to the S2 backend support code, and applications may provide some kind of documentation browsing facility or the ability to generate static files containing documentation.