XL (programming language)

Not to be confused with XL (XML programming language).
XL
Paradigm Multi-paradigm, Concept-oriented, imperative, functional
Designed by Christophe de Dinechin
Developer Christophe de Dinechin
First appeared 2000
Stable release
0.1 / February 2010 (2010-02)
Typing discipline strong
OS Unix-like
License GPLv2
Website xlr.sf.net
Influenced by
Ada, C++

XL stands for eXtensible Language. It is the first and so far the only computer programming language designed to support concept programming.[1]

XL features programmer-reconfigurable syntax and semantics. Compiler plug-ins can be used to add new features to the language. A base set of plug-ins implements a relatively standard imperative language. Programmers can write their own plug-ins to implement application-specific notations, such as symbolic differentiation, which can then be used as readily as built-in language features.

Language

XL is defined at four different levels:

XL has no primitive types nor keywords. All useful operators and data types, like integers or addition, are defined in the standard library (XL2). XL1 is portable between different execution environments. There is no such guarantee for XL2: if a particular CPU does not implement floating-point multiplication, the corresponding operator definition may be missing from the standard library, and using a floating-point multiply may result in a compile-time error.

The Hello World program in XL looks like the following:

 use XL.TEXT_IO
 WriteLn "Hello World"

An alternative form in a style more suitable for large-scale programs would be:

 import IO = XL.TEXT_IO
 IO.WriteLn "Hello World"

A recursive implementation of factorial in XLR looks like the following:

 0! -> 1
 N! -> N * (N-1)!

Syntax

Syntax is defined at the XL0 level. The XL0 phase of the compiler can be configured using a syntax description file, where properties like the text representation and precedence of operators are defined. A basic syntax file defines common mathematical notations, like + for addition, with the usually accepted order of operations.

The parse tree consists of 7 node types, 4 leaf node types (integer, real, text and symbol) and 3 internal node types (infix, prefix and block).

With the default syntax file, the following is valid XL0, irrespective of any semantics.

A = B + "Hello"

It parses as:

infix("=",
      symbol("A"),
      infix("+",
            symbol("B"), text("Hello")))

Semantics of XL1

The XL1 phase is defined as a sequence of operations on the XL0 parse tree. These operations are provided by various compiler plug-ins, that are triggered based on the shape of the parse tree.

Special constructs, translate and translation, are provided by a plug-in designed to facilitate the writing of other plug-ins. The quote construct generates a parse tree. Here is how these notations can be used to implement a plug-in called ZeroRemoval that eliminates superfluous additions and multiplications by zero.

translation ZeroRemoval
  when
    'X' + 0
  then
    return X
  when
    'X' * 0
  then
    return parse_tree(0)

A plug-in can be invoked on a whole file from the command line, or more locally in the source code using the pragma notation, as follows:

X := {Differentiate} d(sin(omega * T) * exp(-T/T0)) / dT

The XL1 phase contains a large set of plug-ins, notably XLSemantics, that provide common abstractions like subroutine, data type and variable declaration and definition, as well as basic structured programming statements, like conditionals or loops.

Type system

XL1 type checking is static, with generic programming abilities that are beyond those of languages like Ada or C++. Types like arrays or pointers, which are primitive in languages like C++, are declared in the library in XL. For instance, a one-dimensional array type could be defined as follows:

generic [Item : type; Size : integer] type array

A validated generic type is a generic type where a condition indicates how the type can be used. Such types need not have generic parameters. For instance, one can declare that a type is ordered if it has a less-than operator as follows:

// A type is ordered if it has a less-than relationship
generic type ordered if
  A, B : ordered
  Test : boolean := A < B

It is then possible to declare a function that is implicitly generic because the type ordered itself is generic.

// Generic function for the minimum of one item
function Min(X : ordered) return ordered is
  ... compute Y of type ordered ... 
  return Y

This also applies to generic types that have parameters, such as array. A function computing the sum of the elements in any array can be written as follows:

function Sum(A : array) return array.Item is
  for I in 0..array.Size-1 loop
    result += A[I]

Type-safe variable argument lists

Functions can be overloaded. A function can be declared to use a variable number of arguments by using ... in the parameter list (historically, the keyword other was used for that purpose). In such a function, ... can be used to pass the variable number of arguments to another subroutine, a feature now called Variadic templates:

// Generic function for the minimum of N item
function Min(X : ordered; ...) return ordered is
  result := Min(...)
  if X < result then
    result := X

When such a function is called, the compiler recursively instantiates functions to match the parameter list:

// Examples of use of the Min just declared
X : real := Min(1.3, 2.56, 7.21)
Y : integer := Min(1, 3, 6, 7, 1, 2)

Expression reduction: operator overloading

Operators can be defined using the written form of function declarations. Below is the code that would declare the addition of integers:

function Add(X, Y: integer) return integer written X+Y

Such written forms can have more than two parameters. For instance, a matrix linear transform can be written as:

function Linear(A, B, C : matrix) return matrix written A+B*C

A written form can use constants, and such a form is more specialized than a form without constants. For example:

function Equal(A, B : matrix) return boolean written A=B
function IsNull(A : matrix) return boolean written A=0
function IsUnity(A : matrix) return boolean written A=1

The mechanism is used to implement all basic operators. An expression is progressively reduced to function calls using written forms. For that reason, the mechanism is referred to as expression reduction rather than operator overloading.

Iterators

XL iterators allow programmers to implement both generators and iterators.

import IO = XL.UI.CONSOLE

iterator IntegerIterator (var out Counter : integer; Low, High : integer) written Counter in Low..High is
    Counter := Low
    while Counter <= High loop
        yield
        Counter += 1

// Note that I needs not be declared, because declared 'var out' in the iterator
// An implicit declaration of I as an integer is therefore made here
for I in 1..5 loop
    IO.WriteLn "I=", I

Development status and history

XL is the result of a long language design work that began around 1992. The language was designed and implemented primarily by Christophe de Dinechin.

Historically, the XL compiler was written in C++. It had achieved a point where most of the features described above worked correctly, but writing plug-ins was a nightmare, because C++ itself is not extensible, so implementing translate-like statements was impossible. The parse tree was more complicated, with dozens of node types, because it was designed for cross-language support. Moka was a Java-to-Java extensible compiler using the same infrastructure.

Abandoning the cross-language objectives and complex parse-tree structure, a complete rewrite of the compiler was started in 2003. The parse tree was vastly simplified down to the seven XL0 nodes types now in use. This new compiler bootstrapped in 2004, and all new development is now written in XL. However, this new compiler still has somewhat incomplete XL1 support, although its abilities already exceed C++ in a few areas.

Ancestry

XL1 was inspired by a large number of other languages. In alphabetical order:

Semantics

XLR is a dynamic language, originally intended as a back-end for the XL1 compiler, hence the name, which stands for XL runtime. It shares the basic XL0 syntax with XL1, but its behavior is much closer to a functional language, whereas XL1 is intended to look mostly like an imperative language. XLR has practically only one built-in operator, "->", which denotes a rewrite. The notation on the left of the rewrite is transformed into the notation on the right of the rewrite.

This mechanism is used to implement standard notations:

 if true then TrueBody else FalseBody -> TrueBody
 if false then TrueBody else FalseBody -> FalseBody

References

  1. Manchester, Phil (2008-01-16). "Dip into Concept Programming". The Register. Retrieved 2010-02-03.
This article is issued from Wikipedia - version of the 10/11/2016. The text is available under the Creative Commons Attribution/Share Alike but additional terms may apply for the media files.