A possible solution to the Lisp/JavaScript impedance

Please use this forum to post feedback and suggestions related to QCAD.

Moderator: andrew

Post Reply
Pixel_Outlaw
Newbie Member
Posts: 3
Joined: Wed Aug 24, 2022 8:07 pm

A possible solution to the Lisp/JavaScript impedance

Post by Pixel_Outlaw » Wed Aug 24, 2022 8:26 pm

I'm relativity new so please forgive any assumptions I've made in error.

I noticed that we have JavaScript support for scripting, which honestly is great in a CAD especially at this price point. Kudos there.
I also noticed that a lot of people are requesting AutoLISP/VisualLISP support.

Being a huge Lisp guy (Emacs Lisp, Common Lisp, Scheme, Clojure and AutoLISP) I'm wondering if anyone has thought about using one of the "compiles to JavaScript" approaches to add Lisp functionality in? I'm a programmer so I DO appreciate the complexity of such a task.

The hard part of course is that you can't model the Direct X/Visual Brainsick side of Visual LISP (nor should we repeat that kind of cruft).
Instead, I think it would be good to use something like ParenScript and define a few of the AutoLISP functions. (quite trivial since you can literally define new syntax and functions at runtime in Common Lisp) we can also make it have 1:1 parity with JavaScript functionality.

Now, I'm willing to contribute some effort into this regard as a programmer if there is interest.
There are differences between Common Lisp and Visual Lisp but you're gaining a TON of modern features with such a conversion.
It would be fairly straight forward though to convert most VisualLISP routines into Common Lisp after a brief tutorial on their differences.

Just tossing this out there, as a multi dialect Lisp guy. :mrgreen:

Pixel_Outlaw
Newbie Member
Posts: 3
Joined: Wed Aug 24, 2022 8:07 pm

Re: A possible solution to the Lisp/JavaScript impedance

Post by Pixel_Outlaw » Thu Aug 25, 2022 4:59 am

Bit of an update.
Here is the definition of a VisualLISP function transformed into valid Common Lisp.
I've actually added new syntax to the language from within the language so it understands AutoLISP's defun.

Code: Select all

;; Macro that handles AutoLISP defun in Common Lisp
(defmacro vl-defun (name arglist &body body)
  (let* ((split-/ (position '/ arglist)))
    (multiple-value-bind (parameter-list locals-list)
        (if split-/
            (values (subseq arglist 0 split-/)
                    (cdr (subseq arglist split-/)))
            (values arglist nil))
      `(defun ,name ,parameter-list
         (let ,locals-list
           ,@body)))))


;; VisualLISP defun with local "vars"
(vl-defun do-thing (foo bar / baz quux)
  (setq baz 100)
  (setq quux 200)
  (print (list foo bar baz quux)))


;; Valid Common Lisp expression generated from vl-defun below
(DEFUN DO-THING (FOO BAR)
  (LET (BAZ QUUX)
    (SETQ BAZ 100)
    (SETQ QUUX 200)
    (PRINT (LIST FOO BAR BAZ QUUX))))

CVH
Premier Member
Posts: 3416
Joined: Wed Sep 27, 2017 4:17 pm

Re: A possible solution to the Lisp/JavaScript impedance

Post by CVH » Thu Aug 25, 2022 7:11 am

Hi,

I'm not a LISP guy, I learned to write QCAD scripts on the fly.
I can not agree that LISP is easy to read ... Simply because I don't master the syntax.
Nor do I have any knowledge on how to 'AutoLISP' under ACAD.

From the Parenscript Reference Manual I do understand that LISP itself can be translated to JavaScript.
What I don't understand directly is how that should be implemented under QCAD.
We could simply run the translation with Run Script (XC) of course ... :roll:

I don't see a 1 on 1 functionality between the ACAD AutoLISP dialect to the QCAD ECMAScript methods.
Vars, arrays, if/then ... Program flow ...
... All that is fine but what with e.g. trimming an entity at a certain point in space ...
... Adding a line, arc, circle ... Constructing a polyline from segments ... :?
Are you going to replace/translate every ACAD instruction with relevant code to do the same under QCAD?
https://qcad.org/doc/qcad/3.0/developer/index.html

I have no clue what the given example code would do ...
I think you should start with comparing an existing QCAD script with how that is achieved under ACAD.
Let's take a standard example that draws 3 dots where you want them:
QCAD GUI: Misc .. Script Examples .. Draw .. Three Points (P3)
https://github.com/qcad/qcad/blob/maste ... ePoints.js
Remark here that the folder structure is mandatory for an Addon ...
... What is not required for a simple 'hit and run' macro/script.

Next would be to translate a simple AutoLisp macro to a functional ECMAScript that does the same under QCAD.

The final question is then: Can one translate every existing AutoLISP code to work under QCAD :?: :!:

If you have questions about scripting under QCAD, I would be glad to help you where I can. :wink:
Just post them here:
https://qcad.org/rsforum/viewforum.php?f=30

Regards,
CVH

Pixel_Outlaw
Newbie Member
Posts: 3
Joined: Wed Aug 24, 2022 8:07 pm

Re: A possible solution to the Lisp/JavaScript impedance

Post by Pixel_Outlaw » Fri Aug 26, 2022 1:59 am

CVH wrote:
Thu Aug 25, 2022 7:11 am
Hi,

I'm not a LISP guy, I learned to write QCAD scripts on the fly.
I can not agree that LISP is easy to read ... Simply because I don't master the syntax.
Nor do I have any knowledge on how to 'AutoLISP' under ACAD.

From the Parenscript Reference Manual I do understand that LISP itself can be translated to JavaScript.
What I don't understand directly is how that should be implemented under QCAD.
We could simply run the translation with Run Script (XC) of course ... :roll:
I'm not quite sure myself since I'm not a JavaScript guy. :)
I think the first step would be seeing if I can make valid JavaScript from some Common Lisp source code via ParenScript.
If that's the case at the most minimum I can just load those directly.
I'm still in the tinkering phase myself. You CAN hook Common Lisp directly into your project with something like ECL which is hosted in C programs.
The downside is that it's meant to be hosted in C so it doesn't know about C++'s classes and sometimes an additional layer needs to be written.

I can give you maybe 80% of the Lisp syntax in 1 line it's actually built on lists. Lists make up the syntax with symbols and atoms.
The function below is a list. The first element is treated as a function and the rest are parameters that it gets applied to.

Code: Select all

(foo (+ 1 2) (* 3 4) "hello")
We can see 3 lists here which will get evaluated. Two nested inside a main one. Denoted by ( ... )
The first list has the symbol foo, which will reference a function called foo.
It will apply that to the 3 items inside, two lists and a string.

Code: Select all

(+ 1 2)
is a list with + in the function position. It will return the sum of 1 and 2.

Code: Select all

(* 3 4)
is a list with the function * in function position. It will return the product of 3 and 4.
"hello" is a string it will evaluate to itself.
The final result is calling the function foo with the parameters 3 12 and "hello".
It would look like so to the Algol family of languages

Code: Select all

foo(1 + 2, 3 * 4, "hello")
It may seem very very odd to build a language on nested lists. But there is a side effect.
We can rearrange the data inside to define new syntax via macro as I did above. 8)
VisualLISP doesn't have macros though, it's a weak Lisp.
CVH wrote:
Thu Aug 25, 2022 7:11 am
I don't see a 1 on 1 functionality between the ACAD AutoLISP dialect to the QCAD ECMAScript methods.
Vars, arrays, if/then ... Program flow ...
... All that is fine but what with e.g. trimming an entity at a certain point in space ...
... Adding a line, arc, circle ... Constructing a polyline from segments ... :?
Are you going to replace/translate every ACAD instruction with relevant code to do the same under QCAD?
https://qcad.org/doc/qcad/3.0/developer/index.html
This is a very good point. I think it'd be best to adopt the AutoCAD syntax but leave the functions to QCAD analogs.
Luckily Lisps are defined in terms of themselves. From a few simple forms springs everything.
Usually the core language is very small, and you can design additional functions at any time that create new syntax.
The users' code is literally on the same level as the core language.
CVH wrote:
Thu Aug 25, 2022 7:11 am
I have no clue what the given example code would do ...
I wrote some very mid-high level code for that one, I understand.
Essentially, what I wrote allows you to define new functions in Common Lisp as if they were being defined in AutoLISP.
I added new syntax to the Reader (the part that transforms code into different code).
The Reader now hits this new form vs-defun and does transformations to turn it into Common Lisp's defun (define function) on the fly.
CVH wrote:
Thu Aug 25, 2022 7:11 am
I think you should start with comparing an existing QCAD script with how that is achieved under ACAD.
Let's take a standard example that draws 3 dots where you want them:
QCAD GUI: Misc .. Script Examples .. Draw .. Three Points (P3)
https://github.com/qcad/qcad/blob/maste ... ePoints.js
Remark here that the folder structure is mandatory for an Addon ...
... What is not required for a simple 'hit and run' macro/script.

Next would be to translate a simple AutoLisp macro to a functional ECMAScript that does the same under QCAD.

The final question is then: Can one translate every existing AutoLISP code to work under QCAD :?: :!:

If you have questions about scripting under QCAD, I would be glad to help you where I can. :wink:
Just post them here:
https://qcad.org/rsforum/viewforum.php?f=30
Regards,
CVH
I agree with your approach and think it's sensible.
On the topic of translating every AutoLISP function into QCAD, it's not easily feasible.
Too much of their stuff is based around their workflow and Direct X.
However, it is possible to provide a familiar Lisp syntax for working with QCAD's workflow.
The way I see it, there are two concerns here.
1. The syntax of VisualLISP (what makes Lisp Lisp)
2. The integration with AutoCAD (what allows you to manipulate the drawing).

I'm more concerned with the first, I think the best approach is to provide a familiar syntax (for we weirdos) that mirrors QCAD's workflow.
There may be some functions that have a 1:1 parity between both.

Post Reply

Return to “QCAD Suggestions and Feedback”