Software and Languages


XPL is a functional language that has been developed to experiment with Domain Specific Languages and Language Oriented Programming.  It is written in Java. The source code for XPL v 0.1 can be downloaded here. The language has first-class grammars that can be combined and has access to its own abstract syntax. Grammars use quasi-quotes to build new syntax structures that can be inserted into execution stream. This is like macros in Scheme (in that language features can be defined with a limited scope). However unlike Scheme XPL can define completely new language syntaxes. Here is a simple example inspired by an example by Martin Fower:

export test1,test2
// We need syntax constructors for Record and Field:

import 'src/xpl/exp.xpl'

// We need list operations:
//    take([1,2,3],2) = [1,2]
//    drop([1,2,3],2) = [3]
//    foldr(f,g,b,[1,2,3]) = g(f(1),g(f(2),g(f(3),b)))

import 'src/xpl/lists.xpl'

// Define some functions to be used as args to foldr:

combine(left,right) = [| fun(l) ${left}(l,fun(r,l) r + ${right}(l)) |]
id(x) = x
empty = [| fun(l) {} |]

// Define a function that constructs *the syntax* of a field extractor:
//    extractor('name',5) = [| fun(l,k) k({name=asString(take(l,5))},drop(l,5)) |]

extractor(n,i) =
let record = Record([Field(n,[| asString(take(l,${i})) |])])
in [| fun(l,k) k(${record},drop(l,${i})) |]
// Define the grammar to consists of a sequence of fields.
// Each field builds an extractor. All extractors are combined
// into a mapping from a sequence of character codes to a record:
grammar = {
fields -> fs=field* { foldr(id,combine,empty,fs) };
field -> n=name whitespace ':' i=int { extractor(n,i) };
int -> whitespace n=numeric+ { Int(asInt(n)) };
whitespace -> (32 | 10 | 9 | 13)*; 
name   -> whitespace l=alpha ls=alpha* { asString(l:ls) }; 
alpha  -> ['a','z'];
numeric -> ['0','9']

// Here is a use of the language: a customer is a name (5 chars) followed
// by an address (15 chars), follower by an account number (3 chars):

customer =
  intern grammar {
// The customer map is used by applying it to a stream of char codes:

input = [102,114,101,100,32,49,48,32,77,97,105,110,32,82,111,97,100,32,32,32,53,48,49] 
test1() = customer(input)

// Just to show everything is first-class:

test2() = map(customer,repeat(input,10))
To use XPL you download the ZIP file. It is developed as an Eclipse project, but can also be run stand-alone. The interpreter is in the xpl package in the source folder. If you run the Interpreter as a Java application in Eclipse then the console becomes an XPL top-level loop that you can type XPL commands to. Here is a transcript of the example given above:

[src/xpl/xpl.xpl 2353 ms,136]
> import 'src/xpl/split.xpl';
[src/xpl/split.xpl 179 ms,262]
[src/xpl/exp.xpl 26 ms,404]
[src/xpl/lists.xpl 108 ms,164]
> test1();
{customer=fred ;address=10 Main Road   ;account=501}
> test2();
[{customer=fred ;address=10 Main Road   ;account=501},{customer=fred ;address=10 Main Road   ;account=501},{customer=fred ;address=10 Main Road   ;account=501},{customer=fred ;address=10 Main Road   ;account=501},{customer=fred ;address=10 Main Road   ;account=501},{customer=fred ;address=10 Main Road   ;account=501},{customer=fred ;address=10 Main Road   ;account=501},{customer=fred ;address=10 Main Road   ;account=501},{customer=fred ;address=10 Main Road   ;account=501},{customer=fred ;address=10 Main Road   ;account=501}]
There is currently no user documentation (contact me if you are interested in this). But there are some technical articles: language modules in XPL, modular interpreters in XPL, and parsing infix operators using XPL. In addition the source code contains a number of examples in the xpl folder.