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 the XPL 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 the syntax of each new language feature.
Here is a simple language feature inspired by an example from Martin Fowler. Suppose that we get a stream of character codes as input. The stream contains information about customers and we need to chop up the input to produce data records. If there are a large number of different types of input data and they change regularly then it makes sense to define a declarative language construct that defines each type. The following XPL code defines a language construct for recovering structure from an input stream:
Here is a simple language feature inspired by an example from Martin Fowler. Suppose that we get a stream of character codes as input. The stream contains information about customers and we need to chop up the input to produce data records. If there are a large number of different types of input data and they change regularly then it makes sense to define a declarative language construct that defines each type. The following XPL code defines a language construct for recovering structure from an input stream:
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), followed by an account number (3 chars): customer = intern grammar { customer:5 address:15 account:3 } // 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 (link above). 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 (user input after a '>' followed by XPL output):
[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.
No comments:
Post a Comment