2017-10-09

sescript

s-expression language that compiles to javascript/ecmascript

supports all javascript and ecmascript and future forms. there is a quote form to insert arbitrary script strings

mostly a 1:1 mapping from sescript to ecmascript - sescript is ecmascript

a simpler ecmascript syntax

optional return keyword. the last evaluated expression is returned

use scheme-typical identifiers with the characters "-", "->", "?", "!" and more

command-line compiler and scheme library

ses-include form to include uncompiled sescript files. optionally with the use of load-paths from a $SES_LOAD_PATH environment variable

translates to unformatted code for faster processing and saved complexity.

--format and --compress option on the command-line if uglifyjs is installed

javascript module support with an r6rs library-form that creates module.js module definitions

sescript only outputs valid ecmascript syntax. since modern javascript interpreters run-time errors with context, and particularly if the generated code is auto-formatted, finding the source of errors is not more difficult to find than with plain ecmascript

status: stable, been around for a while, easy to maintain and extend

questions, change requests, and issues are currently best communicated per email (see start page)

mirrored on github

code examples

echo "(define (test) #t)" | ses
->
"use strict";var test=(function(){return(true)});
(define myobject (object a 1 b (object c 2)))
(let (d (+ myobject.b.c 1))
  (if (= 3 d) d #f))

function chaining with arguments

(chain on (ref switches 0) "mousedown" (l () (primitive-activate this switches switched config)))
->
switches[0].on(mousedown,(function(){return(primitive_activate(this,switches,switched,config))}));

define a module.js module. exported bindings will be in the global object "sph.value-change-status". requires module.js to be previously loaded, it is not included. completely optional

(library (calculator color)
  (export
    update-multi-preview)
  (import)
  
  (define (update-multi-preview create-colors name)
    (define colors (create-colors))
    (colors.shift)
    (text-display-lines.push "" name)
    (_.times colors.length
      (l (index) (define color (ref colors index))
        (define input-id (string-append "input_" name "_value_" index))
        (define preview
          (document.querySelector (string-append "." name " .preview[for=" input-id "] .area")))
        (define value (document.getElementById input-id))
        (text-display-lines.push (color.toRgbString))
        (set! value.value (color->rgb-comma-string color)
          preview.style.backgroundColor (color.toHexString)))))
  
  (export update-multi-preview))

command-line application

$ ses

parameters
  options ... paths ...
description
  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
options
  --compress | -c  compress output with uglifyjs
  --format | -f  format output with uglifyjs
  --help | -h
  --interface

installation

dependencies

manual

install all dependencies if there are some

download

download

alternatives: releases, git clone git://sph.mn/sescript

unpack

unpack the downloaded archive

for example

tar -xf sescript.tgz

-x is for extract

-f is for the source file name

install

cd sescript
su root
./exe/install

in most cases the installer only copies files

the install script might have a "--help" option that will list more install options

pacman

using aurget:

aurget -S --deps sescript-git

filename extension for source files

.sjs may be appropriate. .ses could also work

possible enhancements

syntax-transformers - let-syntax, define-syntax and similar

remove some default built-ins because they conflict with eventual user definitions

there might be a significant difference between javascript anonymous functions assigned to variables and functions created using the function syntax

external

other languages that compile to javascript

character conversions in identifiers

- _

a? a_p

a! a_x

a->b a_to_b

(the character conversions are the c identifier conversion conventions used by guile)

syntax

sescript-expression and the script result. taken from the automated tests

(lambda (a) 1)
->
(function(a){return(1)});

((lambda (a) 1))
->
(function(a){return(1)})();

(let (a 1) 2)
->
(function(a){return(2)})(1);

(let ((a 1) (b 2)) #t)
->
(function(a,b){return(true)})(1,2);

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

(if a (if b c d) e)
->
(a?(b?c:d):e);

(if a (if (if b c) d) e)
->
(a?((b?c:undefined)?d:undefined):e);

(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)});

(declare a)
->
var a;

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

(lambda (a b . c) c)
->
(unquote (string-append (function(a,b){var c=new Array(arguments.length);for(var ___i=2; ___i<arguments.length;___i+=1) {c.push(arguments[___i])}return(c)});))

(set! a 1)
->
a=1;

(ref a 1)
->
a[1];

(ref a 1 2 3)
->
a[1][2][3];

(ref (ref a 1) 2)
->
a[1][2];

(pair 1 (list))
->
[].unshift(1);

(first (list))
->
[][0];

(append (list 1 2) (list 3 4))
->
[1,2].concat([3,4]);

(append a b)
->
a.concat(b);

(tail (list 1 2))
->
[1,2].slice(1);

(array 1 2 3)
->
[1,2,3];

(list 1 2)
->
[1,2];

(object a 2 b 3)
->
{"a":2,"b":3};

(environment a b c)
->
{"a":a,"b":b,"c":c};

(chain c (chain a b) 1 2 "d")
->
b.a().c(1,2,"d");

(object)
->
{};

(new Obj 3 5)
->
new Obj(3,5);

(not 1)
->
!1;

(if (not 1) a b)
->
(!1?a:b);

(and 1 2 3)
->
(1&&2&&3);

(= 1 2 3)
->
(1==2==3);

(equal? a 1)
->
(a===1);

(begin 1 (begin 2 3))
->
1;2;3;

(cond ((= a 1) (equal? b 2)) ((equal? c 3) #t))
->
((a==1)?(b===2):((c===3)?true:undefined));

(cond ((= a 1) (equal? b 2)) ((equal? c 3) #f #t) (else #t #f))
->
((a==1)?(b===2):((c===3)?(false,true):(true,false)));

(case (+ 1 2) (2 #f) (3 #t))
->
(function(___v){return((((___v===2))?false:(((___v===3))?true:undefined)))})((1+2));

(case (+ 1 2) (2 #t #f) (3 #t) (else 4 5))
->
(function(___v){return((((___v===2))?(true,false):(((___v===3))?true:(4,5))))})((1+2));

(guard (exc (else #f)) 1)
->
(function(){try{return(1)}catch(exc){return(false)}})();

(guard (exc (#t 1) (test 2)) 3 4)
->
(function(){try{3;return(4)}catch(exc){return((true?1:(test?2:undefined)))}})();

(guard (exc (#t 1) (test 2) (else 5)) 3 4)
->
(function(){try{3;return(4)}catch(exc){return((true?1:(test?2:5)))}})();

(library (a b c) (export d e) (import (f) (g)) 1 2 3)
->
module.define("a.b.c",["f","g"],(function(exports){1;2;3;return(exports({"d":d,"e":e}))}));

(library (a b c) (export d e) 1 2 3)
->
module.define("a.b.c",[],(function(exports){1;2;3;return(exports({"d":d,"e":e}))}));

(with-libraries ((a b c) (d e) (f g)) 1 2 3)
->
module(["a.b.c","d.e","f.g"],(function(){1;2;3;return(undefined)}));

(map (lambda (a) #t) (array 1 2 3))
->
[1,2,3].map((function(a){return(true)}));

(fold f (array) (array))
->
[].reduce((function(___proc){return((function(prev,e,index,arr){return(___proc(e,prev,index,arr))}))})(f),[]);

(each (lambda (ele) ele) (array))
->
[].forEach((function(ele){return(ele)}));

(string-join (array "a" "b") "/")
->
["a","b"].join("/");

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

(length (list 1))
->
[1].length;

(string-append "a" "b" "c")
->
("a"+"b"+"c");

(quote "var a = 3")
->
var a = 3;

(let loop ((a 1) (b 2)) (loop (+ a 2) (+ b 1)))
->
(function(loop){loop=(function(a,b){return(loop((a+2),(b+1)))});return(loop(1,2))})();

(apply a 1 2 (list 3 4))
->
a.apply(this,[1,2].concat([3,4]));

(return)
->
return;

(return 1 2)
->
return(1,2);

(if 1 (lambda () #t) 2)
->
(1?(function(){return(true)}):2);

(l () (define a 3))
->
(function(){var a=3;return(undefined)});

(l () (begin 1 2))
->
(function(){1;return(2)});

(set! a 1 b 2 c 3)
->
a=1;b=2;c=3;

(l () (set! a 1 b 2 c 3))
->
(function(){a=1;b=2;return(c=3)});

(l () (set! a 1))
->
(function(){return(a=1)});

(throw "test")
->
(function(){throw(["\"test\""])})();

(list #\a)
->
["a"];

(list "\"")
->
["\""];

(list #t)
->
[true];

import name

(sph lang sescript)

exports

ses-default-load-paths

variable

sescript->ecmascript

procedure

signature

exprs port [load-paths] ->

(expression ...) port ->

sescript->ecmascript-string

procedure

signature

expr [load-paths] ->

expression -> string

sescript-use-strict

procedure

signature

port ->

port -> string

description

writes a "use strict"; command to port to the following

code to be interpreted in the so called strict-mode.

this can appear multiple times in the output without being an error

sph-lang-sescript-description

variable

tags: programming guile library scheme overview start q1 javascript computer project compiler ecmascript sescript