Language proposal: dave
I've been a long time user of PHP, but have issues with it for obvious reasons. After extensively using Node.js and Python as well as a fair amount of research into other languages I've decided to give writing my own a shot. I'm rather inexperienced in language design (although I do find compilers fascinating), have very little time on my hands at the moment and there are about fifty other options – as such I don't really expect this to be a resounding success and replace PHP (although I do hope it does). Its an interesting experiment nonetheless.
The principles which guide Julia gave me a very clear picture of their language design. Along similar lines:
- Free and open source (MIT licensed)
- Built-in string encoding (html, url, sql, ...)
- Scoping from javascript (single user thread)
- Function parameters from python (named, list, dict arguments)
- Curly-brace language, but no-semicolons
- Automatic lazy network/file access for easy pipelining
The easiest way I can think of to explain the language is with some example programs written in it:
/* hello.dave: A standard hello world program */ print "Hello, world!"
/* encoding.dave: A quick look at dave's string encoding */ var heart = '<3', bobby = "Robert') DROP TABLE Students; --", hello = 'Hello, world!" print heart // <3 print "$heart" // <3 print html:"$heart" // <3 print html:"<strong>$heart</strong>" // <strong><3</strong> print sql:"SELECT * FROM Students WHERE name=$bobby" // SELECT * FROM Students WHERE name='Robert\') DROP TABLE Students; --' print url:"http://cowsay.morecode.org/say?format=text&message=$hello" // http://cowsay.morecode.org/say?format=text&message=Hello%2C+world%21 var boldheart = html:"<strong>${"<3"}</strong>" print html:"I $boldheart built-in encodings -- $heart." // I <strong><3</strong> built-in encodings -- <3. print html:"Double encoded: ${"$boldheart"}." // Double encoded: <strong>&lt;3</strong>
/* functions.dave: A little like python */ // Using a map just to demonstrate its capability var toUpperCase = {'a':'A', 'b':'B', 'c':'C', 'd':'D', 'e':'E', 'f':'F', 'g':'G', 'h':'H', 'i':'I', 'j':'J', 'k':'K', 'l':'L', 'm':'M', 'n':'N', 'o':'O', 'p':'P', 'q':'Q', 'r':'R', 's':'S', 't':'T', 'u':'U', 'v':'V', 'w':'W', 'x':'X', 'y':'Y', 'z':'Z'} var toLowerCase = {v:k for k,v in toUpperCase.items} function transform(letter, map) { // Non-existant entries are === undefined, similar to javascript // <a> ?: <b> is equivalent to <a> ? <a> : <b> return map[letter] ?: letter } function join(seperator, *items) { if (!items) return '' result = items.pop(0) for item in items: result += "$seperator$item" return result } function capitilise(string) { return join('', transform(string[:1], map=toUpperCase), *[transform(c, map=toLowerCase) for c in string[1:]]) } params = {'string': 'hello, world!'} print capitilise(*params)
/* database.dave: An example web server with blocking database connections */ var redis = import('redis').Redis(), mysql = import('mysql').MySQL(server='localhost', username='josh', password='abc', database='snap'), http = import('http'), url = import('url') http.createServer(handleResponse).listen(1337, '127.0.0.1') function handleResponse(req, res) { var pageviews try { // The following three lines will return instantly, and will only block once the values are used in output var info = mysql.fetchSingle(sql:"SELECT * FROM person WHERE name=${url.parse(req.url).query.name}") var pageviewKey = "count-pageviews:${info.id}" pageviews = redis.incr($pageviewKey) } catch (mysql.NoSingleException e) { res.end(html:"Sorry, we couldn't find you in our database :(") return } // As we attempt to send the string the interpreter will wait for the redis query to finish // The MySQL command would have blocked before as its exception was caught above res.end(html:"<h1>Hey ${info.name}</h1>": "<p>According to our database you are <strong>${info.age}</strong> years old.</p>" "<p>(you have viewed at this $pageviews times)</p>") }
/* pipeline.dave: fetch a lot of data from redis and then process it later */ var redis = import('redis').Redis() _ = import('mystringlib') values = [] for k in range(1000) { values.push(redis.get("${_.sprintf('count-%04d', k)}")) } // We'll get to this point before we have retrieved the data from redis print values.reduce(function(sum, x) { return sum+x; }, 0)