Giter Site home page Giter Site logo

lispx's Introduction

LispX

Copyright (c) 2021, 2022 by Manuel J. Simoni

License: MIT

Status: Work in progress, but mostly stable. Using it successfully in a bunch of personal projects.

Build and Test

yarn install && yarn build && yarn test

About

LispX is a new Lisp I am developing to make web programming bearable.

It has three main parts:

  • LispX’s raison d’être is to solve JavaScript’s async problem. It does this with delimited continuations. It faithfully implements the delimcc API as well as delimited dynamic binding by Oleg et al. and can run the full test suite from the delimcc distribution. With continuations, all async JS APIs (promise- and callback-based) can be used as if they were synchronous.

  • As the language core, LispX uses vau calculus developed by John Shutt for his Kernel language. Vau calculus is essentially a lambda calculus without implicit evaluation of arguments (sometimes called "call-by-text"). Vau calculus turns the usual programming/metaprogramming dichotomy on its head: metaprogramming is the default, and ordinary programming the boring special case.

  • As the "user interface", LispX uses the same classic Lisp syntax, naming conventions, and overall organisation as Common and Emacs Lisp. It is a Lisp-2, is fully object oriented with single inheritance (defclass), has single-dispatching generic functions (defgeneric, defmethod), the usual simple control forms (catch, throw, block, return-from, unwind-protect, loop, dotimes, dolist, …​), and implements large parts of the CL condition system (handler-bind, handler-case, restart-case, signal, error, invoke-restart, invoke-restart-interactively, compute-restarts, …​). The condition system is of course written in LispX itself and is a good demonstration of LispX programming in practice: src/cond-sys.lispx.

Example

(defun sleepsort (numbers)
  (dolist (n numbers)
    (coroutine (sleep n) (print n))))

Implementation characteristics

  • The implementation is about 2000 lines of JS and 1000 lines of Lisp (as measured by cloc).

  • Clean and well-documented code.

  • The build is < 20 KB (minified and gzipped).

  • There are more than thousand unit tests.

  • The architecture is a tree-walking interpreter so it’s not a speed demon, but it’s fast enough for many apps, especially GUIs.

  • Readable Lisp stack traces.

  • Easy to interface with JS.

  • Works practically everywhere (browsers, Node, Deno, QuickJS, Duktape, …​)

Code map (most important files)

  • src/vm.mjs — Core VM data structures like objects, classes, symbols, environments, etc.

  • src/eval.mjs — Evaluation of core forms like def, vau, progn, if, etc.

  • src/control.mjs — Evaluation of delimited and simple control forms.

  • src/read.mjs — Reader code.

  • src/boot.lispx — Language bootstrap. This also documents all built-ins until I put together a reference manual.

  • src/cond-sys.lispx — Condition system.

  • src/js.lispx — JS interface.

Debugger example

$ ./scripts/node-repl
Welcome to LispX!
* (+ 100 x)
Debugger invoked on condition:
#<unbound-symbol-error :environment #<environment> :message "Unbound variable: x" :symbol x>
Available restarts -- use (invoke-restart 'name ...) to invoke:
continue
use-value
store-value
abort
Backtrace:
x
(#<function> 100 x)
(%eval form environment)
(eval (read) repl:+environment+)
(#<function> (eval (read) repl:+environment+))
(print (eval (read) repl:+environment+))
[1] (invoke-restart 'use-value 42)
142
*

Language notes

Strings

UTF-8.

Numbers

Arbitrary-precision decimals.

Booleans

#t and #f — only booleans can be used with if etc.

Functions returning booleans end in p.

Nil

#nil is only the empty list and not a boolean, symbol, or marker for an absent value.

Void

#void is used for absent values, e.g. returned by an empty (progn).

Options

We use options throughout instead of nil-punning.

An option is either nil or a one-element list.

Functions returning options end in ?.

(get? '(:bar 1 :foo 2) :quux)
=> ()
(get? '(:bar 1 :foo 2) :foo)
=> (2)

Forms like if-option are used for destructuring:

(if-option (value (get? '(:bar 1 :foo 2) :foo))
  value
  3)
=> 2

Namespaces

There are three namespaces: variable (no particular read syntax), function (sharpsign single-quote), and class (sharpsign caret).

Unlike in CL, function (and class) symbols can also be used on the left-hand side of definitions and as parameters:

(def #'foo (lambda ())) has the same effect as (defun foo ()).

Lisp-1/2

LispX combines the advantages of Lisp-1 and Lisp-2.

We can call functions received as arguments without the need for funcall by using function symbols as parameters:

(defun compose (#'f #'g)
  (lambda (x) (g (f x))))

If it’s not a symbol, the operator position of a form is evaluated normally, as in Lisp-1:

((compose (lambda (x) (+ 1 x)) (lambda (x (* 3 x))) 10)
=> 33

Uniform compound definiends

The left hand side of definitions and parameter forms can be not only symbols but also nested lists. This provides a uniform solution for destructuring and multiple values without any special forms such as multiple-value-bind.

(def (x y) (list 1 2))
x
=> 1
y
=> 2

#ignore is used to ignore unneeded data:

(let (((((#ignore . rest))) '(((1 2 3)))))
  rest)
=> (2 3)

If you think that let has too many parentheses, LispX might not be for you.

lispx's People

Contributors

dependabot[bot] avatar manuel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

mcarifio

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.