j.yud.co.za

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:

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"
// &lt;3

print html:"<strong>$heart</strong>"
// <strong>&lt;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>&lt;3</strong> built-in encodings -- &lt;3.

print html:"Double encoded: ${"$boldheart"}."
// Double encoded: &lt;strong&gt;&amp;lt;3&lt;/strong&gt;
/* 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)