compiles s-expressions to javascript/ecmascript
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.

  • a simpler ecmascript/javascript syntax. ecmascript written as scheme-like s-expressions
  • the output, after formatting, is supposed to be as if originally written in ecmascript
  • supports all ecmascript 5
  • command-line compiler and scheme library
  • possibly also useful as an intermediate language for applications that want to compile to ecmascript
  • status: should work, been around for a while, easy to maintain and extend
  • license: gpl3+. does not apply to generated code. generated code has your license
  • homepage


echo "(define (test x y) (return #t))" | ses
function test(x, y){return(true)};
(declare d e f)

(define myobject
    a 1
    b (object c 2)))

  d 1
  e 3
  f 9)


(get myobject "a" "b")
(get myarray 0 1)


  • adds return statement to the last expression in a function. lambda just feels wrong without this behaviour
  • let, let*

command-line application

$ ses --help
  options ... paths ...
  compile sescript to ecmascript. read from files or standard input,
  and write to a file or standard output depending on if paths are given as arguments.
  input/output depends on the number of given paths:
  none: read from standard input and write to standard output
  one: read from file and write to standard output
  two: read from the first file and write to the second
  more: read from all files except the last one and write to the last one
  --compress | -c  compress output with uglifyjs
  --format | -f  format output with uglifyjs
  --help | -h



run the installer, see ./exe/install --help


  • copy everything under modules/ into a directory that is in guiles default load path or $GUILE_LOAD_PATH
  • copy exe/ses to /usr/bin or wherever executables are to be installed

try to run ses --help to see if it works

usage from scheme

(import (sph lang sescript))


(sescript->ecmascript-string (quote (begin (define a 1) (set a 2))))
(sescript->ecmascript (quote ((define a 1) (set a 2))) (current-output-port))

(define scheme-value 8)

(define code
      (define a 1)
      (set a (unquote scheme-value)))))

(sescript->ecmascript-string code)


how to add your own syntax: this is currently only possible when compiling from scheme and not via the cli application. create a scheme file with new bindings, example below, and then use sescript->ecmascript-string or similar as usual

(import (sph lang sescript) (rnrs hashtables))

(hashtable-set! ses-descend-sescript (quote myprefix)
  (lambda (a compile)
    "(any:sescript-argument ...) procedure:recurse -> any:sescript
    create sescript that will be parsed again"
    (list (quote if) a #t #f)))

(hashtable-set! ses-descend-ecmascript (quote myprefix)
  (lambda (a compile)
    "(any:sescript-argument ...) procedure:recurse -> string:ecmascript
     create ecmascript strings directly"
     (string-join (map compile a) "\n")))

(sescript->ecmascript-string code)


  • filename extension .sjs or .ses
  • --format and --compress option on the command-line if uglifyjs is installed
  • js-beautify is another recommended auto formatter
  • sescript only outputs valid ecmascript syntax
  • a benefit of using sescript is that editor modes for scheme syntax and structural editing can be used
  • other languages that compile to javascript

syntax reference

ses expression and the ecmascript result. taken from the automated tests

(array #\a)

(array "\"")

(array #t)

(begin a->b a-b a! a& a?)

(case a ((b c d) #t))
switch(a){case b:case c:case d:true;break};

(begin 1 a #t #\a "1")

(begin 1 (begin 2 3))

(case (+ 1 2) (2 #t #f) (3 #t) (else 4 5))
switch(1+2){case 2:true;false;break;case 3:true;break;default:4;5;break};

(= 1 2 3)

(and 1 2 3)

(array 1 2 3)

(chain c (chain a b) 1 2 "d")

(cond (a b) ((= c 3) #f #t) (else #t #f))
if(a){b}else if(c===3){false;true;}else{true;false;};

(cond (a b))

(declare a)
var a;

(declare a b c)
var a,b,c;

(define a 1)
var a=1;

(define a 1 b 2)
var a=1,b=2;

(define a (lambda (a b) 1 2 3))
var a=(function(a,b){1;2;return(3);});

(define (a b c-d) 1 2 3)
function a(b,c_d){1;2;return(3);};

(for ((set index 0) (< index len) (set index (+ 1 index))) #t)

(for (((set a 0) (set b 1)) (< index len) ((set a (+ 1 a)) (set b (+ 2 b)))) #t)

(for ((begin a b) (< c d) (begin e f)) #t)

(get a 1)

(get a 1 2 3)

(get (get a 1) 2)

(if* a (if* b c d) e)

(if* a (if* (if* b c) d) e)

(if* 1 (lambda () #t) 2)

(if* (not 1) a b)

(lambda (a) 1)

(lambda () (if* a b c))

((lambda (a) 1))

(let (a 1) 2)

(let ((a 1) (b 2)) #t)

(let* ((a 1) (b 2) (c 3)) 4)
(function(a){var b=2;var c=3;return(4);})(1);

(make-regexp "[^a-b0-9]" "g")

(new obj)
new obj();

(new obj 3 5)
new obj(3,5);

(not 1)

(nullary #t)


(object a 2 b-c 3 "d" 4)

(object* a b c)


(return 1 2)

(ses-comment "test" "comment")
/* test
  comment */

(ses-insert "var a = 3")
var a = 3;

(set a 1)

(set a 1 b 2 c 3)

possible enhancements and ideas

  • support docstrings
  • add a command-line option to load custom syntax extensions from a file
  • translate scheme comments. scheme comments dont appear in the output, only (ses-comment "comment string") or ses-insert can be used
  • syntax checks and error messages
  • an extension that supports hygienic macros and a scheme like module system. implement do-while as an example