This is a draft description of the scripting language Lilacs.

Lilacs is a LISP inspired little language that compiles into JavaScript. It is initially designed to be used as the server side scripting language in the Git Blogger system.

Language specification

Special forms

  • =>

      (x y ... => body1 ... body2)
      ->
      (function (x, y ...) {
          body1;
          ...
          return body2;
      })
    

    or this alternative form to allow recursion:

      ([func] x y ... => body1 ... body2)
      ->
      (function func(x, y ...) {
          body1;
          ...
          return body2;
      })
    
  • exact

      (exact var)
      ->
      var
    
      (exact obj/field)
      ->
      obj.field
    
  • new

      (new func arg1 arg2 ...)
      ->
      new func(arg1, arg2 ...)
    
  • @@

      (@@ idx arr)
      ->
      arr[idx]
    
      (@@ key obj)
      ->
      obj[key]
    
  • if

      (if a b c)
      ->
      if (a) { return b; } else { return c; }
    
  • case

      (case k 
        ((a ... b) body1)
        ((c ... d) body2)
        (else body3))
      ->
      (function () {
          switch (k) {
          case a:
          ...
          case b:
              return body1;
          case c:
          ...
          case d:
              return body2;
          default:
              return body3;
          }
      })()
    

    you can specify multiple expression bodies and omit the else clause. it would be equivalent with the following:

      (case k
        ((a ... b) body1 ... body2))
      ->
      (case k 
        ((a ... b) (begin body1 ... body2))
        (else (throw% "case matching failed")))
    
  • w% (w% as an alternative of w/, which comes from “with handler”)

      (w% (handler fin) body1 ... body2)
      ->
      (function () {
          try {
              body1;
              ...
              return body2;
          } catch (__lilacs_e) {
              return handler(__lilacs_e);
          } finally {
              fin();
          }
      })
    

    you can also omit fin.

    as an obvious observation, you should avoid using __lilacs_e as a variable name in your code.

  • throw%

      (throw% e)
      ->
      (function () { throw e; return; })()
    

Special constants

  • #undefined -> undefined
  • #null -> null
  • #t -> true
  • #f -> false

Syntax sugars

  • let

      (let ((x var1) (y var2) ...) body1 ... body2)
      ->
      ((x y => body1 ... body2) var1 var2)
    
  • begin

      (begin body1 ... body2)
      ->
      ((=> body1 ... body2))
    
  • for

      (for (x arr) body1 ... body2)
      ->
      (arr/map (x => body1 ... body2))
    
  • for-in

      (for-in (k v obj) body1 ... body2)
      ->
      ((__lilacs_obj =>
          ((Object/keys __lilacs_obj)/map
              (k => (let ((v (@@ k __lilacs_obj))) body1 ... body2)))) obj)
    

    which is basically the same as

      ((Object/keys obj)/map (k => (let ((v (@@ k obj))) body1 ... body2)))
    

    but make sure obj is only evaluated once.

    note that this doesn’t have the same behavior as the for ... in ... loop in JavaScript. See the JavaScript documentation for Object.keys for more information.

    also as an obvious observation, you should avoid using __lilacs_obj as a variable name in your code.

  • @-shorthand

      (@func :A a ... :B b :: p1 ... p2)
      ->
      (_shat/func {:A a ... :B b} [p1 p2])
    
      (obj/@method :A a ... :B b :: p1 ... p2)
      ->
      (obj/_shat/method {:A a ... :B b} [p1 p2])
    

    with this shorthand, it provides a standard yet convenient and clear way to define and use functions that generates HTML tags. e.g:

      (@ul :class "fancy-list" ::
        (@li :: (@a :href "/article-1" :: "article-1"))
        (@li :: (@a :href "/article-2" :: "article-2")))
    

Numbers

Lilacs recognizes numbers as JavaScript does. Thus 345, 34.5, 3.45e2, 0377, 0xFF, 0xff, Infinity, NaN are all valid numbers in Lilacs.

Strings

Lilacs only recognizes double quoted strings, and uses the same escaping sequences as JavaScript. Additionally, Lilacs support its own form of raw string literal enclosed between ::! and !::. Raw string literal can also be post-processed if needed.

::!
raw string
 second line
!::
->
"raw string\n second line"

::! func
raw string
 second line
!::
->
(func "raw string\n second line")

Regular expressions

Currently, Lilacs doesn’t have specific grammar for regular expressions, but you can create regular expressions with the RegExp class:

(new RegExp "https?://.+")
->
new RegExp("https?://.+")

Invocation

(func arg1 arg2 ...)
->
func(arg1, arg2 ...)

(obj/method arg1 arg2 ...)
->
obj.method(arg1, arg2 ...)

Access

var
->
var

obj/field
->
obj.field

Assignment

Lilacs provides assignments to work with the rest of JavaScript world, but it’s usage is discourage.

(<- var val)
->
var = val

Object creation

{:key1 val1 :key2 val2 ...}
->
{key1 : val1, key2 : val2 ...}

Array creation

[a b ...]
->
[a b ...]

Operators

Lilacs provides polish style operators for the following JavaScript’s binary operators with the same name:

+, -, *, /, %, >, >=, <, <=, &&, ||, &, |, ^, <<, >>, >>>

and the following with a different name:

  • eq? -> ==
  • eq?? -> ===

  • neq? -> !=
  • neq?? -> !==

and also the following unary operators with the same name:

+, -, !, ~

Lilacs doesn’t provide assignment arithmetic operators on purpose, nor increment/decrement operators.