Giter Club home page Giter Club logo

jscl's People

Contributors

abeaumont avatar brpocock avatar cxxxr avatar davazp avatar diogoalexandrefranco avatar equwal avatar ermineii avatar eudoxia0 avatar ferada avatar foretspaisibles avatar gleefre avatar hemml avatar henryirvine avatar henrys1 avatar jnjcc avatar kengruven avatar kidd avatar maxwellhansen avatar mishoo avatar nagy avatar nikodemus avatar orodley avatar plonk avatar puercopop avatar rayslava avatar samebchase avatar stylewarning avatar uthar avatar vitovan avatar vlad-km 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jscl's Issues

incf semantic

CL incf semantics is different from what jscl provides; for example

(let ((x 0))
    (incf x (setf x 1))
    x)

should return 2 in a CL implementation and instead jscl returns 1.

Not sure how easy this would be to fix because in Javascript x=0; x += (x = 1); results in 1.

The subtlety is that (incf x y) where x and y are arbitrary expressions is not evaluated "left-to-right", but the evaluation of x is split in two steps: evaluating the place and getting the value. The place x is evaluated before y, but the value of x used for incf is evaluated after y.

Function wrappers around variadic builtins

Various functions in JSCL, such as CAR and CONS are defined as builtins, and the function definition is simply a wrapper around this builtin, so that they are first-class objects. The definition therefore looks like:

(defun cons (x y) (cons x y))

I was attempting to do the same for <, >, etc. How would this work with variadic functions such as these?

Attempting to do the same as above:

(defun < (x y) (< x y))

would restrict it to only two arguments. Using APPLY:

(defun < (x &rest args) (apply #'< x args))

wouldn't work, as APPLY expects a function, not a builtin. Should I just redefine the functions myself, like:

(defun < (x &rest args)
  (while args
    ...  ))

? Or is there some other solution I'm missing?

Standard symbol collisions

It is useful to use another name for existing functions in the host Lisp implementation. So we will be able to use it and test it interactively without compiling JSCL once and again.

We could use ! to prefix such symbols and rename them in the end of the bootstrap.

FFI to Javascript

Currently, we have the internal js-vset and js-vref special forms, as well as oget and oset functions to reference Javascript variables and access to Javascript objects respectively. We have not special forms to call Javascript functions and access Javascript objects yet.

It would be to clean this interface, add the missing features and export it in a FFI package.
If you want to take this, please discuss the API here.

RFC: OO system - CLOS or other?

Hi,

I've been (slowly) working away at a very simple OO system to help implement streams per #56. It's based around alists and closures: very simple, very minimal & inefficient algorithms to get things going.

While it's very enjoyable & instructive building an OO system, I'm wondering if this is something worth pursuing beyond just basic scaffolding to make streams play nice.

Essentially, should JSCL support CLOS, or should it have its own OO system? I don't know the licensing definitions for extant CLOS implementations and also the effort level to integrate them into a Lisp system.

It might be fun from a hacking perspective to investigate systems like Flavors and T and have a core "jscl:system-object" substrate which all the object systems support at core.

Anyway, RFC.

Documentation: which Lisp is ECMALisp?

Is ECMALisp intended to be Common Lisp or an approximation thereof?

Answering this question would allow people to choose to use/contribute to ECMALisp (or not) based on their preferences for CL.

(/ 1 0) Hangs

Seems like TRUNCATE is called infinite times by INTEGER-TO-STRING..
Not sure, but I think the problem is that in javascript 1/0 is Infinity, which in fact is a number (typeof Infinity == 'number'). ¿Any ideas?

Error loading jscl into CCL

Reported by Alexander Shendi. It yields:

Script started on Wed 01 May 2013 02:48:58 AM UTC
Welcome to Clozure Common Lisp Version 1.9 (LinuxARM32)!
? (load "jscl.lisp")
;Compiler warnings for "src/read.lisp" :
; In READ-FLOAT: Undeclared free variable IT (4 references)

Error: Undefined function COLLECT called with arguments ((DEFUN BINDING-NAME (X) (UNLESS (BINDING-P X) (ERROR "The object is not a type BINDING")) (NTH 1 X))) .
While executing: DEF!STRUCT, in process listener(1).
Type :GO to continue, :POP to abort, :R for a list of available restarts.
If continued: Retry applying COLLECT to ((DEFUN BINDING-NAME (X) (UNLESS (BINDING-P X) (ERROR "The object is not a type BINDING")) (NTH 1 X))).
Type :? for other options.
1 > (quit)

Surprising symbol-uninterning behaviour in tests

Tried to add a test:

(test (= 42 (progn
              (eval '(defun test-fun (x y)
                      (+ x y)))
              (eval '(test-fun 40 2)))))

Turns out TEST-FUN and Y end up uninterned, causing a somewhat opaque error in the js console: [18:53:49.921] uncaught exception: Variable `G597' is unbound.

(Added a PRINT around the expansion of the DEFUN to observe this.)

DEFMACRO doesn't create closures

CL-USER> (flet ((a () ())) (defmacro b () (a)))
B
CL-USER> (b)
ERROR: Function `A' is undefined.

The defined macro should close over the function bound by FLET. Closures over functions in other cases seem to work fine though, e.g.:

CL-USER> (defvar foo (flet ((a () ())) (lambda () (a))))
FOO
CL-USER> (funcall foo)
NIL

so I think it's just an issue with DEFMACRO

EQUAL

Currently EQUAL is quite broken... e.g.

(equal '(1 2) '(1 2)) ==> nil

I tried to provide a better implementation (IIUC now is just javascript "==", a basically useless operator) but failed.

Where should be placed an implementation of EQUAL? I don't think I understand the boot process used by jscl.

Add keyword arguments to lambda-lists

Use the recent support of keyword symbols to implement keyword arguments to functions. It is probably better not to support &allow-other-keys and :allow-other-keys-p in the beginning, to keep it simple.

Can you enumerate some things which you explicitly consider out-of-scope for JSCL?

In the README you specify that JSCL will remain a subset, which implies that there are things you consider to be a bad match for what you want JSCL to do.

One of the things that I would like to see clarified is the future of numbers; do you intend to stick with js numbers only, extend them with eg. complexes, or do you plan on untangling integers and floats and implementing all of CL's number types?

(I think there are perfectly valid reasons for picking any of these -- depending on your goals. I'm absolutely not trying to imply that you should implement the whole panoply of numeric types.)

Calling FUNCTION on the name of a built-in function returns NIL

For example:

(function car)
#<FUNCTION>
(function rplaca)
ERROR: Function `RPLACA' is undefined

Interestingly, in src/list.lisp, many built-in functions (like CAR and CDR) are redefined (with DEFUN) using their built-in functions of the same name, which suggests we could simply wrap all built-in functions with normal functions.

That does work for fixing RPLACA in this particular case, but I'm not sure that's the right solution overall.

read-symbol problems

Currently the reader has a problem with symbol name escaping. For example

|abc:def|

is read by CL as a regular symbol, the same as

abc\:def

In a similar way you can have a symbol that contains terminal characters, like

\:-\)

a symbol with name ":-)"

The current approach for reading symbols is skip characters up to the first terminal (with hardcoded terminal meaning) and then pass the string to read-symbol that will split on ":" to find an optional package name.

Is jscl instead aiming at the same (and more complex) reading rules of cl?

The difference in behaviour between readers creates also different code when cross-compiling using CL to javascript in respect to using jscl compiled compiler.

Random not implemented

The RANDOM function, MAKE-RANDOM-STATE, etc are not implemented.

I think RANDOM could probably just be a thin wrapper around javascript's Math.random()?

DO macro usage

I got stuck today compiling a function that used a DO* loop, and kept whittling away at it until I had a pretty minimal DO loop:

(defun jscl-breaker ()
  (do ((x))
    (t 'result)))

In SBCL, this returns the symbol RESULT, which is what I expect. In JSCL, I get "ERROR: syntax error".

The compiled JS line that it's unhappy with seems to be:

return ();

but I haven't investigated enough to find out exactly where this is coming from.

Split of boot.lisp

Currently all kind of forms are being defined in boot.lisp, but as supported forms increase so will be this file. I propose to split this file in different ones separated by topic, which should follow CLHS chapter structure, i.e. numbers.lisp should contain forms in numbers dictionary, conses.lisp those in conses dictionary, and so on.

REMOVE-IF-NOT does not like vectors

CL-USER> (remove-if-not (lambda (x) (> x 1)) '(1 2 3 4))
(2 3 4)
CL-USER> (remove-if-not (lambda (x) (> x 1)) #(1 2 3 4))
ERROR: Not a number!

Proper character and string implementation

Characters are just integers right now

#\newline => 10

Strings are implemented using literal Javascript strings. It is nice for FFI, but it is not correct as Javascript has inmutable strings.

Arithmetics on lists

Why arithmetic operations are applied only to two arguments?

I tried to rewrite it like

(defun plus (&rest args) 
  (if args 
     (+ (car args) (apply #'plus (cdr args))) 
     0))

But argument counter considers that it can't be more than two :(

Incorrect handling of non-local control transfers

Looking at the generated code I noticed that exceptions used for non-local control transfers (e.g. return-from) use a numeric ID related to lexical context to recognize the jump target.

This is not correct in case of recursive functions. For example with

(defun foo (x)
  (when x
    (funcall x))
  (foo (lambda ()
         (return-from foo 1)))
  (return-from foo 2))

calling (foo NIL) should return 1 (like it does on SBCL) and not 2 (like it does on JSCL) because the return-from in the lambda should exit the toplevel foo and not only the nested call.

The solution I implemented for this problem in my lisp dialect targeting javascript is to use a unique object (an empty array) created on tagbody entry to identify jump targets so that a closure capturing a target will properly handle recursive functions.

Streams...

Streams aren't implemented.

http://www.lispworks.com/documentation/lw51/CLHS/Body/v_debug_.htm#STstandard-outputST

I'm inclined to create an ad-hoc closure-based object system to handle streams. standard-output, *error-output, and trace-output would be linked up to the existing WRITE function in JSCL via one of those closures. It doesn't appear that JSCL supports input-via-cl quite yet.

A number of other functions such as make-*-stream should also be supported with this adhoc system.

Would appreciate comments on this approach.

One concern I have is that it might be good to wait until DEFSTRUCT is implemented.

Javascript code generator

Calls to the compiler generate Javascript code directly. Several tricks are used to make sure composability. For example, a construction like

(function(){
...
    return ...;
})()

is used very often in order to return only Javascript expressions. However it yields very verbose code. Writing a Javascript unparser would fix this problem and would allow some useful features like minimization.

Reader doesn't detect invalid dotted lists

Dotted lists missing the final close-paren aren't detected by the reader:

CL-USER> '(1 . 2
(1 . 2)
CL-USER> '(1 2 3 4 . 5
(1 2 3 4 . 5)

There's also an unhelpful error message in the case where the list element after the dot is missing entirely:

CL-USER> '(1 .
ERROR: `"G1"' is not a symbol.

Investigate using SICL

Since it seems you are interested in implementing a complete CL (issue #40), it might be interesting to evaluate modules of the language in SICL that are complete and whose dependencies are already satisfied. These projects seem complementary to me in that SICL is largely an implementation of a high-quality, conforming, shared CL standard library and JSCL is a new and growing implementation in need of one. This could be a very exciting and energizing collaboration for both projects.

Location of non-essential functions

I was going to implement some of the long list of trivial missing functions, but I'm unsure about where they belong in the source tree. Should I just add a new file in src with related functions in it, add a :target entry to *source* and add the functions I defined to the export list in toplevel.lisp? Or is there some other place they should go? Maybe a HACKING/CONTRIBUTING file in the root directory would be useful to explain this.

Reading a list of numbers

There is a special case for #. in %read-list that I don't understand and that creates a bug when reading a list with floating point numbers without integral part.

(read-from-string "(1 .25)") ==> (1 . 25)
(read-from-string ".25") ==> 0.25

EDIT

Fixed in my repo. Changes read.lisp and tests/read.lisp.

(cl:def!struct ..) appears to freeze

Javascript appears to freeze when executing the below code, according to firefox, asking me if I want to kill it.

This occurs at both:

1a37f5c Merge branch 'dump-changes-bug'

e12774f Rename AUTHORS to CREDITS and add an entry for Nikodemus Siivola

Welcome to JSCL!

CL-USER> (cl:def!struct foo bar)

Smarter string dumping

Use single-quoted or double-quoted for literal strings depending on the string content.

Benchmarking

It would be good to have a benchs/ directory with some benchmarking. It is similar to tests/ but for measuring the performance. Nothing sophisticated, but I want to improve the compiler with some optimizations and measures are needed.

Loop Macro

Looking at the old MIT/symbolics loop macro implementation http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/iter/loop/symbolix/, written in ANSI lisp. I hacked on it a bit, and it seems like it might work in JSCL, but it depends on having &optional handled correctly in defmacro lambda lists.
Currently the following fails when it tries to compile-funcall on ((head-var ...

(defmacro with-loop-list-collection-head ((head-var tail-var &optional user-head-var) &body body)

   (let ((l (and user-head-var (list (list user-head-var nil)))))
         `(let* ((,head-var (list nil)) (,tail-var ,head-var) ,@l)
              ,@body)))

Bad keyword arguments give incorrect error message

The error-checking for keyword arguments gives an incorrect error message, when passed an unknown keyword:

CL-USER> (make-array 3)
#(NIL NIL NIL)
CL-USER> (make-array 3 :element-type t)
#(NIL NIL NIL)
CL-USER> (make-array 3 :element-type t :oops 55)
ERROR: Unknown keyword argument ELEMENT-TYPE
CL-USER> (make-array 3 :oops 55)
ERROR: x is undefined

It looks like it might be an off-by-one error, but I'm not sure where.

Apostrophes in docstrings

Put a function like this in one of the Lisp source files:

(defun f ()
"let's go"
())

and run (jscl:bootstrap). In jscl.js, this gets compiled to:

    func.fname = 'F';
    func.docstring = 'let's go';

which obviously fails to run.

When done in the "JSCL.html" repl, it also fails: "ERROR: missing ; before statement".

Compile macros properly in host

So far we have been using lists to store the macros and dump them to the output file in the bootstrap. We should compile the macros in the end of the process and dump reference to the macro-expanders instead.

(SETF (CAR x) y) in tests

I wanted to write a test like this:

(test (let ((x (cons 1 2)))
        (eql (setf (car x) 0) 0)))

The inner expression (without the "test" wrapper) works fine in the repl. The expression as a test, though, gives a failure (in Firefox) like: "TypeError: l2370.fvalue is not a function".

I see I'm not the first person to find this. In tests/list.lisp, there's a comment:

;; (SETF (CAR (CAR FOO)) 0) doesn't work in the test for some reason,
;; despite working fine in the REPL

I don't know the cause yet, but I did discover that in the compiled tests.js, it includes make_lisp_string("%RPLACA"), so it seems like this symbol is not getting connected somehow.

Support for Node.js

It would be great to support node.js to make the development easier. So we would provide both web REPL and console one. Same for tests.

The main limitation is how node.js manages module variables. Node wraps modules with something like

(function (context, module, ...){ // module code is here })(....)

so "global" variables are not global and we can't access them or define new variables from eval. The solution is move all the global variables to an object, which would be exported in node.js. Indeed, it would clean the Javascript namespace too.

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.