Coder Social home page Coder Social logo

lispyscript's Introduction

LispyScript

This package is no longer supported. Do not use.

A Javascript with Lispy syntax and Macros!

Lispyscript is Javascript using a 'Lispy' syntax, and compiles to Javascript.

Features

  • Javscript Semantics
  • Macros
  • Tail Call Optimization
  • Templates
  • Callback Sequence (avoid nested callbacks)
  • Monads
  • Run in browser
  • Server-side and Browser-side REPLs
  • Unit test feature

LispyScript was inspired by Beating the averages.

Contributors

Santosh Rajan santoshrajan.
Balaji Rao [balajirrao] (https://github.com/balajirrao).
Irakli Gozalishvili Gozala.
Darren Cruse darrencruse

Note to Contributors

To build and run the tests do:

npm test

To build all generated files (including the browser bundle) do:

npm run-script prepublish

Note if browserify fails to find your lispyscript module - Consider adding the location of your lispyscript repo directory on your $NODE_PATH.

Change Log

Version 1.0.0, 6 Nov 2015

Added sitemap support. Added in browser repl. Added watch option to lispy command. Improved run option for lispy command.

Simplified browser usage.

Version 0.3.6, 11 Jul 2013

Simplified browser usage.

Version 0.3.5, 1 Jul 2013

Added browser example in examples folder.

Version 0.3.4, 29 Jun 2013

Added browser support for lispyscript via browserify.

Version 0.3.3, 26 Jun 2013

Added support for requiring '.ls' files.
Require lispyscript files in javascript

Version 0.3.2, 24 Jun 2013

Removed dependency on amd-loader. Use browserify for browser.
Removed dependency on underscorejs
Refactored code

Version 0.3.1, 4 May 2013

var now supports multiple assignments
Refactored array and object to generate cleaner code
Overall cleaner code generated

Version 0.3.0, 24 Apr 2013

Dropped support for older browsers. (Cleaner code)
Minor bug fix

Version 0.2.9, 14 Oct 2012

Added more options to lispy command
Added arrayInit, arrayInit2d, each2d
Added breakout game example
Added shortcut macros for browser usage
Bug fix for division operator

Version 0.2.8, 8 Oct 2012

Added continuation monad
minor bug fixes

Version 0.2.7, 28 Sep 2012

Added method chaining
Changed cond statement
Added homoiconic expressions for recursive macros
Improved macro error checking

Version 0.2.6, 26 Sep 2012

Added Monads
Added cond (switch) statement

Version 0.2.5, 20 Sep 2012

Bug Fixes

Version 0.2.4, 18 Sep 2012

Added array and object keywords.
Macros follow guidelines now.

Version 0.2.3, 15 Sep 2012

Added Callback Sequence to avoid nested callbacks.
Added Test features for language.
Added Test Suite.
Fixed Browser Compatibility issues.
Bug fixes

Version 0.2.2, 9 Sep 2012

Added tail call optimised loop recur construct
Bug fixes

Version 0.2.1, 12 Aug 2012

Added to docs
Edited docs to for latest version
Added to examples
Minor bug fixes

Version 0.2.0, 11 Aug 2012

Bug fix for usage in browser.

Version 0.1.9, 9 Aug 2012

Added html templates
Added template-repeat-key
Changed template syntax

Version 0.1.8, 6 Aug 2012

Changed comments from "#" to ";".
Made LispyScript browser compliant.
Simplified LispyScript installation.
Added support for stdin -> compile -> stdout.
Added 'template-repeat'.
Added setting array/object elements.
Added chatserver example.
Added a simple Twitter example using expressjs and lispyscript templates.

Initial Release, Version 0.1.6, Jun 20, 2012

lispyscript's People

Contributors

balajirrao avatar darrencruse avatar gozala avatar santoshrajan avatar tehshrike 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  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  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

lispyscript's Issues

member access

Can we have '-' to represent '.' ? As in, (this-member-property) == this.member.property ?
Or that is , this['member']['property'] for symbols of any kind ? Thank you!

js loops (for, while)

Lispyscript almost lets me write straight s-expression flavored JS, but it doesn't allow direct access to js loops for and while. This is perhaps a non-goal, but my use-case requires that I save on the runtime size and performance with direct loops. For now, I'm making do with the following macros, which compile to much larger forms than needed.

(macro forloop (i start n rest...)
  (loop (i) (~start)
    (if (< i ~n)
      (do
        ~rest...
        (recur (+ i 1)))
      null)))

(macro while (condition rest...)
  (loop () ()
    (if ~condition
      (do
        ~rest...
        (recur))
      null)))

Strange REPL behavior

I installed LispyScript 0.3.6 with Node v0.10.24, launched the REPL and tried this :

lispy> (+ 1 2)
3

lispy> (+ 1 2 3)
[Error: Syntax Error
Line no 1]

lispy> (+ 1 2)
[SyntaxError: Illegal return statement]

:-|

publish to npm

please publish this to npm so one can install / start using easily:

npm install -g lispy

Use `;` for comment instead of `#`

All the lispy languages I know use ; character for comments. It seems that it would be much better idea to stick to the same character as all the tools build around lispy languages will be able to handle it properly.

set and get

i've come across a bug in lispyscript with get and set.

the code

(var a {})
(set "obj" a {})
(set  "test " (get "obj" a) 1)

does not produce the expected behaviour. i'd expected something like this

var a = {};
a["obj"] ={};
a["obj"]["test"] = 1;

further more i've seen that it is possible to make a javascript object like this:

{"test":1}

but it is not possible to set function with this:

{"test": (function (x) (* x x))}

but thats not a huge issue since one could use the set function.

clojurescript compatible JS APIs

It would be very nice if lispyscript had API compatible with clojurescript:

;; Method call 
(.open window "http://github.com")

;; Property access
(.-location window)

;; Property setting
(set! (.-location js/window) (+ (.-location js/window) "#foo"))

How to chain methods of a object

Can somebody how to produce the following code:

http.createServer(app).listen(app.get('port'), function(){
  console.log("Express server listening on port " + app.get('port'));
});

How to chain the 'listen' method after the http object ?

Uninstalling

Hello... how can I uninstall lispyscript? I used "npm link" as suggested but now "npm unlink" complains there is no uninstall installed in node_modules...

add a macro to ease the use node.js callbacks?

Was just playing with a little example of walking file directories asyncronously with node.js and it struck me lispyscript might be well positioned to simplify/hide/eliminate the use of callbacks...

I actually tried it out with a little macro and was delighted with how easy lispyscript made it (i'd been playing with generators recently and this was remarkably simple by comparison!!).

Here's my original function in lispyscript using callbacks:

(var fs (require 'fs'))

(function walk (rootDir)
  (fs.readdir rootDir (function (err files)
    (each files (function (file)
      (do
        (var filePath (str rootDir '/' file))
        (fs.stat filePath (function (err stats)
          (if (stats.isDirectory)
            (do
              (console.log 'directory:' filePath)
              (walk filePath))
            (console.log filePath))))))))))

(walk '.')

Here's the same code with a little "await" macro (which I show further down):

(var fs (require 'fs'))

(function walk (rootDir)
  (await files (fs.readdir rootDir)
    (each files (function (file)
      (var filePath (str rootDir '/' file))
      (await stats (fs.stat filePath)
        (if (stats.isDirectory)
          (do
            (console.log 'directory:' filePath)
              (walk filePath))
          (console.log filePath)))))))

(walk '.')

And here's the little "await" macro:

(macro await (result asynccall rest...)
  (~@asynccall (function (err ~result)
    ~rest...)))

As I mentioned above - I was delighted the above macro was so short and actually worked perfectly on the first try!!

I was trying to think if the same macro could work with both callback taking functions and promise-returning functions without the programmer having to use a different macro.

I couldn't think of any way - please others comment if somebody sees a way.

As it is I could easily see their being an "awaitp" for "await promise" as a sister to the above?

Also I obviously have ignored errors in the above I need to correct that. I thought I would have the macro include code to throw the received "err" parameter if it gets one.

    edit:  I had a feeling I was going to look like an idiot for writing the above...
I know exception handling is broken with async callbacks but I keep having 
selective memory wanting it not to be true...  I guess the "handle the err yourself" 
option below should really should be the only option where node callbacks are used(?)  
But something nicer could/should be done where promises or generators are involved.  
Nice article about such things fwiw:  
    https://strongloop.com/strongblog/comparing-node-js-promises-trycatch-zone-js-angular/

But maybe there should be a way to handle the err parameter yourself if you want to... The ideal syntax to me would look like destructuring assignment:

So this if you want to handle the err yourself:

  (await (err files) (fs.readdir rootDir) 

This if you want it to throw if there's an error:

  (await files (fs.readdir rootDir) 

Would that be doable I wonder?

(still learning the finer points of macros - seems to me the above implies in my macro I need some logic distinguishing what form I've gotten as the first "result" argument to the macro. I don't know how to do that ATM).

How to define an asynchronous callback?

I'm not clear on how to define asynchronous callbacks. I tried the function (gotData) below but that doesn't work (never gets invoked).

(d3.csv CSV gotData)

(var gotData
  (function (err data)
    (if err
      (throw err)
      (console.log data))))

Thanks in advance.

add a lispy option for tracing?

Some of the quirks I saw when I tried source maps got me thinking...

What about an option for the lispy command to generate the code in a "trace" mode?

Such that when you run it outputs a trace of the program run?

Where (ideally) this might show the lispy source (and maybe the lispy source line numbers and javascript line numbers? since maybe that's not too hard since the sourcemap support in theory has that available already?)

Not that I've given it much thought - maybe less ambitious but still helpful is just a little api for log statements that are only included in the generated code if you've compiled with this special "debug"/"trace" option enabled?

To be a more concrete - I was thinking about this in the context of the "await" macro I just posted about in issue #56.

What if the macros had some optional trace statements that normally expand to nothing/no-ops but expand to console.log statements - output in the generated code - when the lispy compiler got this "trace" mode option:

So e.g.:

(macro await (result asynccall rest...)
  (trace "await for" ^result "from" ^asynccall)
    (~@asynccall (function (err ~result)
       (trace "got" ^result "from" ^asynccall ":" ~result)
       ~rest...)))

The above is just to illustrate the idea it doesn't actually work of course.

In particular in the above I've used a hypothetical e.g. "^result" to indicate "I want the macro argument as a quoted string" (which is what is needed for a console.log statement).

As opposed to the normal "~result" to get the macro argument unquoted as needed for actual generated code.

is there already a way to do domething similar I wonder?

I can see where the above might be questioned as too simple, but if it were also supported through the "keyword" handling in the "lib/ls.js" file...

And maybe even allowed for a few different tracing "levels".

I could see this being very helpful when developing real programs, esp. where complex control flow and asyncrony is involved.

ReferenceError: define is not defined

I try to require the "lispyscript" module, it throws an error:

> require('lispyscript')
ReferenceError: define is not defined
    at Object.<anonymous> (/home/me/myapp/node_modules/lispyscript/lib/ls.js:8:1)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at repl:1:2
    at REPLServer.self.eval (repl.js:110:21)
    at Interface.<anonymous> (repl.js:239:12)

Strange macro behavior

I'm trying to make a simple macro to save myself some typing:

(macro onload (body...)
  ($ (function ()
       ~@body...
       null)))

(onload
  (alert (+ 1 2))
  (alert (+ 2 3)))

($ (function ()
     (alert (+ 1 2))
     (alert (+ 2 3))
     null))

I expect the onload form to expand into something like the last form there, and then get compiled. But when I compile this I get the following javascript:

// Generated by LispyScript v0.2.9
$(function() {
    alert;
    (1 + 2);
    return null;
});
$(function() {
    alert((1 + 2));
    alert((2 + 3));
    return null;
});

I have no idea what the heck is happening here since Lispyscript macros are a templating language instead of real Lisp macros (and aren't really documented (I think the ~@ char splices?)). Is this a bug or am I doing something wrong?

$.map is not a function in browser

Using the browser-bundle.js generated by lispy -b and the following directory structure:

├── browser-bundle.js
├── index.html
├── serve.js
├── serve.ls
└── square.ls

Where index.html and square.ls are the same as http://lispyscript.com/docs/#browserrunning, and serve.js looks like:

#!/usr/bin/env js
// Generated by LispyScript v1.0.0
var http = require('http');
var url = require('url');
var fs = require('fs');
var path = require('path');
var port = (process.argv[2] || 1337);
var baseDir = __dirname;
(http.createServer(function(request,response) {
    return (function() {
    try {
        var reqUrl = url.parse(request.url);
        var fsPath = [baseDir,path.normalize(reqUrl.pathname)].join('');
        response.writeHead(200,{"Content-Type": "text/html"});
        var fStream = fs.createReadStream(fsPath);
        fStream.pipe(response);
        return fStream.on('error',function(err) {
            response.writeHead(404);
            return response.end();
        });

    } catch (e) {
    return (function(err) {
        response.writeHead(500);
        response.end();
        return console.log(e.stack);
    })(e);
    }
    })();
})).listen(port);
console.log("listening on port",port);

Running ./serve.js will print listening on port 1337, but the loaded page http://localhost:1337/index.html will log an error:

Uncaught TypeError: $.map is not a function
  (anonymous function) @ browser-bundle.js:4040
  (anonymous function) @ browser-bundle.js:40

Any pointers? Am I missing something?

Feature request: quote syntax.

Hi
Can you add quote syntax to expand s-expression to data?

Now I'm trying to use lispyscript with gulp.
Gulp have api like this.

    gulp.task("taskname", function() { doSometing(); })

I'd like to use this api like this using macro.

    (deftask taskname
        (doSomething))

But I can't found the way to convert taskname to "taskname" in macro.

I propose more general solution that implement quote.

I want to use quote syntax like this:

   (quote taskname)

Expand to js like

   "taskname"

Then I can define macro like:

(macro (name rest...)
  (gulp.task (quote ~name) (function () ~rest...)))

fn and obj aliases

Can you please add "fn" as an alias for "function", and "obj" as an alias for "object"

Unexpected token (

$ lispy
lispy> LispyScript REPL v0.2.1
lispy> (function (x) (* x x))
[SyntaxError: Unexpected token (]
lispy> 

Variadic functions

=, !=, !, >, <, <=, >=, +, -, *, /, %, &&, || should take a variable number of arguments, like in Clojure. For example,

(+ 3 4 5)
(= 1 1 2)

lispyscript's ".ls" file extension overlaps with livescript

this is admittedly a low priority thing (I don't know there's anything to be done about it).

but I just wanted to create this issue as a note of this overlap in the use of ".ls" with "livescript" (another compile to javascript language) as can be seen here: http://livescript.net/#usage

I ran into the issue when working on an atom editor preview for lispyscript - the editor kept thinking my file was livescript not lispyscript.

To avoid the conflict in my experimental lispyscript branch (now renamed to "sugarlisp" after discussing with Santosh to avoid confusion with the new Lispyscript 2 effort), I'm supporting both the ".ls" extension for backward compatibility and an alternative (tbd) extension as well.

I just noticed the Lispyscript 2 project is already using ".ls2" so they've avoided the issue anyway:
https://github.com/geekskool/lispyscript2/tree/master/lispytest

Feel free to close this issue if desired - I'd just meant some time back to record the issue and never did.

I guess it's really only a problem in Lispyscript 1 if others want such an atom preview for Lispyscript 1 - in which case adding support for an alternative to the ".ls" file extension might be worthwhile.

Destructuring

Can you please add destructuring similar to Clojure/CoffeeScript/LiveScript.

try catch form is buggy

try special form is pretty strange it expects function form but does not accepts non-inline functions.

String interpolation

Would it be possible to implement string interpolation using a macro? I tried my hand at adding it to ls.js, but that got hairy pretty fast.

enhance "lispy --run" to run .ls files requiring other .ls files (and not leave .js files) ?

For server side lispyscript files I've just been compiling them all to javascript with the lispy command and running the result directly with node given the main .ls file's output .js file.

But I noticed the "lispy -r"/"lispy --run" option, as well as the src/require.ls file in the lispyscript code which appears to install a require extension so that "require" in node can require .ls files directly (with them being compiled to javascript in memory and run without creating a .js file).

But when I tried it on this simple example it doesn't work:

file 1: "subtract.ls":

(set module.exports (function (x y)
    (- x y)))

file 2: "square.ls":

(var sub (require "./subtract.ls"))
    (console.log (sub 13 5))

i.e. I get this error:

$ lispy -r square.ls
~/testdir/subtract.ls:1
(function (exports, require, module, __filename, __dirname) { (set module.expo
^^^^^^
SyntaxError: Unexpected identifier

Note the "(set module.expo" is the original lispyscript trying to be executed by node without ever being translated to javascript.

What I think I see looking at the code is that square.ls is being written to a square.js file (just like you'd compiled using the lispy command) and then that is being run with node, but without that .ls "require extension" plugged into node. That's why lispy -r appears to work for simple examples but breaks if you try and require .ls lispyscript files from within those files.

So I think there's a bug where that src/require.ls file was never required in the actual node process that runs the program with "lispy -r"?

For a little test I created my own little "require.js" file like this:

var fs = require("fs"),
    path = require("path"),
    ls = require("lispyscript");
require.extensions[".ls"] = function(module,filename) {
    var code = fs.readFileSync(filename,"utf8");
    return module._compile(ls._compile(code,path.relative(process.cwd(),filename)),filename);
};

And then this does work:
node -e "require('./require.js');require('square.ls')"

i.e. the .ls code is run and the require from square to subtract works and it completes with no .js files left over on the file system.

Not that I think this is the best or only way to work with lispy (I notice the other issue here about having a "watch dir" option to automatically create js files from .ls files as they're modified I agree that's probably a more useful thing overall).

But I think this other way is useful too - and I think it makes "lispy --run" more useful and understandable. (basically: "lispy --run" is the command you use instead of node if you want to write and use your .ls files as if that's all there is!).

My biggest doubt: to implement the above I probably wouldn't have thought to even spawn a child node process I would have just installed the ".ls" require extension and then run their main.ls file in the very same node process that's running the "lispy" command.

But is there a reason the child process was spawned for the current "lispy -r" that I'm not understanding?

Also if "lispy -r" were changed so it no longer created the .js file as a side effect - would anybody care? I assume nobody depends on that - that's what plain "lispy" is there for right...

undefined is not a function

lispy uses undefined in place of no operation everywhere.
When this is fine in Node, it will produce "undefined is not a function" in browser js console.

Could you use something else that won't produce browser warnings?

coffee like try lispyscript

While I really like the idea of lispy script, but having to requiring node + npm + lispyscript just to give it a try sets a high price I think. Having coffeescript like try lispy-script would probably get a lot more people interested in giving it a try.

Allowing a wider range of characters for identifiers

For example the minus sign, which is a commonly used separator in lisp like languages.
It is not a supported character for identifiers in Javascript, so there should be no conflict. ? and > could be considered, too.

  • a-b could be converted to a_b
  • a->b to a_to_b
  • ? could add a "p" suffix for "predicate". a? would become a_p.
  • ! could add a "x" suffix. something like set! would become set_x

There could also be a generic way to convert characters not supported by javascript. For example by using ".charCodeAt()" unicode values. "a?" could be converted to "a_u63".
It wouldn't really matter how long the variables are if the files get minified.

How to create more complicated macros?

Right now it seems like macro is just kind of a templating engine instead of a full, Lispy macro implementation. For example, what if I wanted a macro that would let me insert some logging between each line of a function? Ideally I'd do something like this (in pseudocode):

(macro traced-function (args rest...)
  (var logs (map (function (n) `(console.log ~n))
                 (range (length rest...))))
  (var interleaved-lines (interleave logs rest...))
  `(function ~args ~@interleaved-lines))


(traced-function (foo)
  (var foo 5)
  (var bar 10)
  (+ foo bar))

Which would macroexpand to:

(function (foo)
  (console.log 1)
  (var foo 5)
  (console.log 2)
  (var bar 10)
  (console.log 3)
  (+ foo bar))

Is this simply not going to happen, and that's what "LispyScript is not a dialect of Lisp. There is no list processing in LispyScript." means? I haven't looked at the implementation, so I don't know how homoiconic LispyScript is...

npm release needed!

The version of lispyscript on npm is two years old. Is all of the development in this repository since then that unstable? When can it be released to npm?

Which version are most users currently using? The one in this repository, or the one on npm?

Does anyone know what all has changed between the last npm release and the current repository state?

Splats...

Can you please add splats, like in CoffeeScript.

Long whitespace indentation on "Try It!"

After fiddling around with the code, the output looks like:

// Generated by LispyScript v0.2.5
                                                                                                        var x = 10;
                                                                                                        var y = 10;
                                                                                                        console.log((x + y));
                                                                                                        x = (x + y);
                                                                                                        var a = function() {
                                                                                                        };

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.