Overview

ParenJS: The Paren Programming Language written in JavaScript

(C) 2013-2014 KIM Taegyoon

Paren is a dialect of Lisp. It is designed to be an embedded language. You can use JavaScript in your Paren program.

ParenJS compiles Paren code to JavaScript and evaluates it.

  • paren.js is required to run generated JavaScript code if ParenJS's built-in function is used.
  • Symbol (variable) names should be valid JavaScript variable names.

Try Paren here: Paren Compiler

Try JavaScript here: Try JavaScript

Usage (Try Paren in a web browser)

Open parenjs.html.

Usage (in HTML)

Using script tag support: Once you include paren.js, any script tags in your document with type="text/paren" will be evaluated.

<script src="paren.js"></script>
<script>if(typeof(paren)==='undefined')document.write('<script src="http://jsutil.sourceforge.net/paren.js"><\/script>')</script>
<script type="text/paren">
(alert "hello")
</script>

You can also evaluate paren code from JavaScript using paren.eval(str).

<script type="text/javascript">
paren.compile(str); // return Paren program compiled to JavaScript
paren.eval(str); // evaluate Paren program
</script>

Reference

Functions and macros:
 ! != % && * + ++ - -- . .get
 [] / < <= == === > >= ^ += -= *= /=
 apply begin ceil char-at chr cons dec def defmacro defn double eval filter
 floor fn for for/s if if/s inc int js length list log
 map new nth pr prn quote rand range read-string return set setfn
 sqrt strcat string strlen type when while ||
Etc.:
 (list) "string" ; end-of-line comment

File

  • paren.js: Paren language library
  • parenjs.html: Try Paren in a web browser

Frequently Asked Questions

  • Lisp-1 or Lisp-2? Lisp-1
  • Scoping rules? Lexical scoping
  • 1-way or 2-way JavaScript interop? 2-way
  • Lisp support for JavaScript objects? Yes
  • Support for tail call optimization? No
  • Reader macros? No
  • Speed penalty relative to native JavaScript? No
  • Unique selling point (i.e. why this rather than one of the other Lisp-to-JavaScript dialects)? Generating readable JavaScript which is hackable. No speed penalty

Examples

Hello, World!

(prn "Hello, World!")

Comment

# comment
; comment

Function

In a function, lexical scoping is used.

> ((fn (x y) (+ x y)) 1 2)
3
> ((fn (x) (* x 2)) 3)
6
> (def sum (fn (x y) (+ x y))) ; (def a b) => var a = b;
undefined
> (sum 1 2)
3
> (fold sum (range 1 10 1))
55
> (defn evenp (x) (== 0 (% x 2)))
undefined
> (evenp 3)
false
> (evenp 4)
true
> (apply + (list 1 2 3))
6
> (map sqrt (list 1 2 3 4))
[ 1, 1.4142135623730951, 1.7320508075688772, 2 ]
> (filter evenp (list 1 2 3 4 5))
[ 2, 4 ]
> (== "abc" "abc")
true
> (set x 1) ; (set a b) => a = b; // global variable
  ((fn (x) (prn x) (set x 3) (prn x)) 4) ; lexical scoping
  x
4
3
1
> (set adder (fn (amount) (fn (x) (+ x amount)))) ; lexical scoping
  (set add3 (adder 3))
  (add3 4)
7

Recursion

> (set factorial (fn (x) (if (<= x 1) x (* x (factorial (dec x))))))
  (for i 1 5 1 (prn i (factorial i)))
1 1
2 2
3 6
4 24
5 120
undefined

List

> (nth 1 (list 2 4 6))
4
> (length (list 1 2 3))
3

Macro

> (defmacro cos (a) (Math.cos a))
  (defmacro infix (a op ...) (op a ...))
  (cos (infix 0 * 1 2))
1

JavaScript interoperability (from Paren)

Paren

> (alert "Hello") ; call an arbitrary function
> (. Math random)
> (Math.random) ; class's static method
0.4780254852371699
> (. Math floor 1.5)
> (Math.floor 1.5)
1
> ([] "abc" "length") ; access field
3
> (def a (new Array))
  (. a push 3)
  (. a push 4)
  a
3,4
> (js "1+2+3") ; evaluate arbitrary JavaScript code
6

Sweep Second Clock

JavaScript interoperability (from JavaScript)

JavaScript

paren.eval("(set a 3)"); // global variable
console.log(a);

=> 3

Project Euler Problem 4

ParenJS version (faster)

(def isPalindrome (fn (s)
  (def len s.length)
  (def to (/ len 2))
  (for/s (def k 0) (< k to) (++ k)
    (if/s (!= (s.charAt k) (s.charAt (- len 1 k))) (return false)))
  true))

(def maxP 0)
(for/s (def i 100) (<= i 999) (++ i)
  (for/s (def j i) (<= j 999) (++ j)
    (def p (* i j))
    (when (isPalindrome (p.toString))
      (when (> p maxP)
        (set maxP p)))))
maxP

=> 906609

More solutions of Project Euler in Paren

99 Bottles of Beer

(for i 99 1 -1
  (prn i "bottles of beer on the wall," i "bottles of beer.")
  (prn "Take one down and pass it around," (dec i) "bottle of beer on the wall."))

Alternative Implementations

  • Paren (Paren running natively)
  • ParenJ (Paren running on the Java Virtual Machine)
  • ParenJS (Paren compiler targeting JavaScript)

License

Copyright 2013-2014 KIM Taegyoon

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.