24

Small Clojure Interpreter

 4 years ago
source link: https://www.tuicool.com/articles/2MnaArF
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Small Clojure Interpreter

A tiny implementation of Clojure in Clojure.

Quickstart

Use from Clojure(Script)

(require '[sci.core :as sci])
(sci/eval-string "(inc 1)") => ;; 2
(sci/eval-string "(inc x)" {:bindings {'x 2}}) ;;=> 3

Use from JavaScript

> const { evalString } = require('@borkdude/sci');
> const opts = {bindings: {f: function() { console.log('hello'); }}};
> evalString("(dotimes [i 2] (f))", opts);
hello
hello

Rationale

You want to evaluate code from user input, but eval isn't safe or simply doesn't work.

This library works with:

:advanced

It is used as the interpreter for babashka .

Status

Experimental. Breaking changes are expected to happen at this phase.

Installation

Use as a dependency:

Usage

Currently the only API function is sci.core/eval-string which takes a string to evaluate and an optional options map.

In sci , defn does not mutate the outside world, only the evaluation context inside a call to sci/eval-string .

By default sci only enables access to the pure non-side-effecting functions in Clojure. More functions can be enabled, at your own risk, using :bindings :

user=> (sci/eval-string "(println \"hello\")" {:bindings {'println println}})
hello
nil

Feature parity

Currently the following special forms/macros are supported: def , fn , function literals ( #(inc %) ), defn , quote , do , if , if-not , when , when-not , cond , let , and , or , -> , ->> , as-> , comment , loop , lazy-seq , for , doseq , case , try/catch/finally . It also supports user defined macros.

More examples of what is currently possible can be found at babashka .

If you miss something, feel free to post an issue.

Caveats

To make the rand-* functions behave well when compiling to a GraalVM native binary, use this setting:

--initialize-at-run-time=java.lang.Math\$RandomNumberGeneratorHolder

Test

Required: lein , the clojure CLI and GraalVM.

To succesfully run the GraalVM tests, you will have to compile the binary first with script/compile .

To run all tests:

script/test/all

For running individual tests, see the scripts in script/test .

License

Copyright © 2019 Michiel Borkent

Distributed under the Eclipse Public License 1.0. This project contains code from Clojure and ClojureScript which are also licensed under the EPL 1.0. See LICENSE.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK