Author Topic: Extending AutoLisp - Let's start with format  (Read 12573 times)

0 Members and 1 Guest are viewing this topic.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Extending AutoLisp - Let's start with format
« on: August 13, 2011, 08:49:56 AM »
While we know ALisp (and even VLisp) is way behind most other flavors some of the added functions can quite easily be made to work using only the normal lisp base we already have. As a start point I wanted to implement the Common Lisp's format function. This is quite a comprehensive convertion function from several different value types into a string. See the help here:
I suppose it would have been a lot simpler if we also had something like regular expressions to play with. But unfortunately the only place we can use them is through ActiveX. And of course then you end up with the lisp function not working on Mac!

Anyhow, I tried to at least do the absolute minimum (i.e. strings, decimals & scientific).
Code: [Select]
(defun rtof (num dec dig / ex m f)
  (setq ex 0 m (< num 0) num (abs num) dig (max dig 1))
  (while (> num (expt 10 dig)) (setq num (/ num (expt 10 dig)) ex  (+ ex dig)))
  (while (< num (expt 10 (- dig))) (setq num (* num (expt 10 dig)) ex  (- ex dig)))
  (strcat (if m "-" "") (rtos num 2 dec) "E" (if (>= ex 0) "+" "") (itoa ex))
)

(defun format (dest str lst / *error* DimZin format-convert format-calc current)
  (defun *error* (msg /)
    (if DimZin
      (setvar 'DimZin DimZin)
    )
    (or (not msg) (wcmatch (strcase msg) "*ESC*,*QUIT*,*EXIT*") (princ (strcat "**Error: " msg)))
  )
  (setq DimZin (getvar 'DimZin))
  (setvar 'DimZin 0)
  (defun format-convert (code val / s n d)
    (cond ((wcmatch code "*[sS]") val)
          ((wcmatch code "*$") (format-convert "2,D" val))
          ((wcmatch code "*[dDeE]")
           (cond ((wcmatch code "*`,*")
                  (setq d (if (wcmatch code "`,*")
                            nil
                            (atoi code)
                          )
                  )
                  (while (wcmatch code "*`,*") (setq code (substr code 2)))
                  (setq n (atoi code))
                  (setq s (if (wcmatch code "*[dD]")
                            (rtos (float (abs val)) 2 d)
                            (rtof (float (abs val)) d n)
                          )
                  )
                  (repeat (- n (strlen (itoa (atoi s)))) (setq s (strcat "0" s)))
                  (if (< val 0.0)
                    (strcat "-" s)
                    s
                  )
                 )
                 ((wcmatch code "#*") (rtos (float val) 2 (atoi code)))
                 ((= (type val) 'REAL) (rtos val))
                 (t (itoa val))
           )
          )
    )
  )
  (defun format-calc (str lst / s)
    (cond (current
           (cond ((wcmatch current "*[DdEeSs$]")
                  (setq s       (format-convert current (car lst))
                        current nil
                  )
                  (strcat s
                          (format-calc
                            str
                            (if (cdr lst)
                              (cdr lst)
                              lst
                            )
                          )
                  )
                 )
                 (t (setq current (strcat current (substr str 1 1))) (format-calc (substr str 2) lst))
           )
          )
          ((wcmatch str "`~*") (setq current "") (format-calc (substr str 2) lst))
          ((eq str "") "")
          (t (strcat (substr str 1 1) (format-calc (substr str 2) lst)))
    )
  )
  (if (atom lst)
    (setq lst (cons lst nil))
  )
  (setq current (cond ((= dest t) (princ (format-calc str lst)))
                      ((= (type dest) 'FILE) (princ (format-calc str lst) dest))
                      ((and (= (type dest) 'SYM) (= (type (eval dest)) 'STR))
                       (setq dest (strcat (eval dest (format-calc str lst))))
                      )
                      (t (format-calc str lst))
                )
  )
  (*error* nil)
  current
)
My next iteration of the code would be to work on Engineering Notation (i.e. having a number like 123456 display as 123.456e03 instead of the usual 1.23456e05). I'm gessing it should work with something like a format code of "~,3E".

Anyone want to give a try at incorporating other features of CL's format function are welcome! Or just simplifying / optimizing / fixing the code of course  8) ... I'm trying to steer clear of the vl-string-* functions to try and make it useful on Mac (or other) as well.
« Last Edit: August 13, 2011, 07:11:10 PM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Extending AutoLisp - Let's start with format
« Reply #1 on: August 13, 2011, 12:28:16 PM »
OK, fixed a small typo, consolidated, created the rtof function (for floating points) and implemented engineering notation:
Code: [Select]
;;; Code updated in original post ;;;As an example:
Code: [Select]
_$ (progn (princ (format nil (strcat "This is ENG notation ~3,3e, while this is normal scientific ~3,e\n"
"and here's decimal ~3,3d, while this is currency ~$,\n"
"and finally a string ~s")
'(123456 76543 34.6 45 "TEST"))) (princ))
This is ENG notation 123.456E+3, while this is normal scientific 7.654E+4
and here's decimal 034.600, while this is currency 45.00,
and finally a string TEST
« Last Edit: August 13, 2011, 07:10:36 PM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Extending AutoLisp - Let's start with format
« Reply #2 on: August 13, 2011, 12:34:15 PM »
Or to illustrate another "fix" I did  :lmao: :
Code: [Select]
_$ (format nil "As int ~d, as decimal ~3d, as engineering ~2,3e, as scientific ~2,e, as currency ~$" 123456)
"As int 123456, as decimal 123456.000, as engineering 123.46E+3, as scientific 1.23E+5, as currency 123456.00"
Allows for repeating the same value in several places in the string.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Extending AutoLisp - Let's start with format
« Reply #3 on: August 13, 2011, 07:14:05 PM »
Actually rereading the CL docs I've just realized I've swapped around the precision & field-length codes. Not to mention I'll need to rethink the way I extract their values as there's a posibility of having more than 2 modifiers per code.

Anyhow, it's getting late  :ugly: ... I'll figure out something at some other time.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9484
Re: Extending AutoLisp - Let's start with format
« Reply #4 on: August 13, 2011, 10:36:54 PM »
I'm not all that great with lisp any more but I would be willing to help as much as I can.

At one time I tried to recruit people to start building a standard library of functions but no one wanted to help. However I did develop a tool to help with the library assembly and use (relating to "code coupling" issues). If you want/need help I will see what I can do but please do not get your hopes up; like I said, I'm a bit out of pratice with lisp.
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

Jeff H

  • Needs a day job
  • Posts: 6075
Re: Extending AutoLisp - Let's start with format
« Reply #5 on: August 13, 2011, 10:49:03 PM »
Not familiar with Lisp either but maybe a way to learn would be to help write a dll using .NET that lisp can call for things not able to do with lisp or hard to deal with.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Extending AutoLisp - Let's start with format
« Reply #6 on: August 14, 2011, 06:35:50 AM »
Se7en & Jeff: Thanks for the interest. Greatly appreciated!
 
 I guess the "best" way would be to go with an ARX route, since those .Net stuff isn't actually "portable" as M$ claims (at least not to Mac/Linux). AFAICT the only way to get something truly "upgraded" for lisp would be to redo the entire Lisp interpreter in ARX. I cannot find any hint anywhere on how to start that!
 
 Anyway, I have been looking at other Lisp dialects and come across ECL (which seems to have promise). Though my C++ skills are rusty to say the least! The last time I did anything in it was in 1998. Recently I've started adding such Lisp-callable functions through .Net, but as there's some issues ... I'm starting to have the opinion that .Net's just not good enough! E.g. not running on Mac (need to compile to dylib through Mono - which still has an issue), unable to call a lisp routine directly (i.e. events / reactors can't be implemented), worse code security than Lisp (since .Net's too easy to decompile), etc. If anyone knows of a way to run DotNet from ACad for Mac, please share! That would make this a whole lot simpler.
 
 The closest thing I could find about implementing a new language in ACad is Kean's block on Python. But again that uses .Net  :ugly:
 
 I was thinking it would be possible to use ECL directly through C++. And it "shouldn't" be a huge transition, since ECL can be incorporated into C. It can even load C libraries/dylib/so directlyso liking to ObjectARX classes would be possible directly from the ECL interpreter. Thereafter the ACad specific defuns (like entget, entmod, etc.) could be implemented in ECL itself - basically wrapping the ObjectARX methods. That way you'd have an AutoLisp/VisualLisp -backwards-compatible interpreter which can now extend and run ObjectARX code. And since ECL is a near full implementation of CL you get the "new" functions from there as bonus!
 
 But the biggest reason I'm starting to think ECL is the way to go is it can already run as interpreter, compile to portable bitcode (i.e. FASL), or use a C compiler to compile to native executable. That way performance would be on par with all the current extension possibilities (even those of direct ObjectARX in C++). Not to mention the code obfuscation requirement (as with .Net's code security issues) becomes a non-issue when you compile.
 
 IMO it should be a way of getting the best of all worlds: Allow old LSP code to run as-is; make new much more powerful addons directly in Lisp; run such as true portable (no need to try and steer clear of the vl stuff which doesn't run on Mac); have a way to get true code security; have near full C++ optimizations; etc. All I can see which might cause hassles is old code using ActiveX connection to outside programs, since wrapping the vla functions to directly connect to ObjectARX could be done direct in ECL; but wrapping to the CreateObject is an infinite task.
 
 Then to go further and redo the VLIDE by replacing it with something like Scintilla. It already has CL code formatting / completion / etc. And finally speaking to the guys from OpenDCL about making an embeddable version of their suite so we can have a visual dialog IDE.
 
 So it should be a way of compiling an ARX library per ACad version, per OS/environment - which should overwrite the Lisp interpreter
 
 This thread is basically me trying to do the idea from the opposite end, though I know it's doomed to failure as much will simply be unavailable! It's like an attempt at making some of the full CL functions available to the distant (read left in the gutter) cousin AutoLisp.  :lmao:
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9484
Re: Extending AutoLisp - Let's start with format
« Reply #7 on: August 14, 2011, 10:51:20 AM »
> redo the entire Lisp interpreter
I was making a AutoLisp Parser (I guess  you would call it a "first step" towards an interpreter). But I know/knew it was a throw-away project before I started it (It was never really going to see the light of day; it was more of an exercise for me).

But back on topic:

I think I found some COM "stuff" (Let me down-play that because I haven't read the docs on it  yet; I just found it 10 minutes ago) so we could in theory tap into all that ARX `stuff'.  I will read the docs later but from what I did read it was very limited. From my readings a while back (aka my memory) g++ doesn't do COM, gcc does but not very well.

I don't have a Mac (I have Linux or BSD) and trying to cross-compile for OS X is just plain stupid, I will have to do some more reading up on the subject and give it some more thought (I'm still waiting for the coffee to finish making).
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

LE3

  • Guest
Re: Extending AutoLisp - Let's start with format
« Reply #8 on: August 14, 2011, 01:37:21 PM »
At least for me - an x-lisper -
Another of why this was not posted at least 10 years ago... when i was way on the mood for lispy stuff... then it could be of interest.

:)

All the luck on this adventure !

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Extending AutoLisp - Let's start with format
« Reply #9 on: August 15, 2011, 09:01:41 AM »
Doing lots of research on the net I've come across an old implementation of Corman Lisp as an ARX module for R14: http://autocad.xarch.at/lisp/cormanlisp/

It's literally the ONLY piece of code (I could find after several hours of searching) which even remotely shows some promise. I've even inspected the DLL/ARX's in the acad folder to see what exported functions they have. Not too sure what's happening inside that vl.arx (which I think is the main lisp interpreter), but at least there's some indication of what's needed in the CLARX.

I've just realized (or rather remembered) why I stopped using C++ so long ago! Looking at that source code it just looks like a mess! But that's C++ isn't it?  :pissed:

Anyhow, the other option is as Jeff's mentioned: Create DotNet/ARX wrappers for lisp to work with the newer objects in the API. Basically doing what ACad should have done at the very least ... instead of wasting their time in designing new bugs to put into the new versions  :ugly:

I'd like some opinions as to which you'd think would be the most efficient & least cumbersome way forward (please give some reasons). So I (or perhaps we  :angel: ) can make an informed decision before going and wasting more time down a path which heads to a cliff-face!  :lmao:
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9484
Re: Extending AutoLisp - Let's start with format
« Reply #10 on: August 15, 2011, 10:11:54 AM »
First things first:
I'm a bit confused as to what exactly is the goal. I understand we want to "extend" Alisp but I think we should determine some hard-fast goals to reach first.

I'm all for the C++ route (I quit doing ALisp to pursue C++ [aka: higher learning] awhile ago) but obviously theSwamp's user base isn't in the same frame of mind any more (It seems most people here/now prefer using a hammer to put frosting on a cake just to show off their hammer-cake-frosting-abilities).

I think we should choose something more along the lines of a STD library of functions that can be used (Like what you started to do above). We would need to address certain issues first but I think that goal could work out to be better in the long run; -e.g. when I tried to start "the standard library project" I knew Reni's Std library had a problem of being highly coupled so I addressed that problem by making a preprocessor (The `better' being that now the ALisp users have a preprocessor to use in development). I also think our efforts may have more participants if we choose a goal that more can help with (like a standard library written in plain ALisp). After we define some solid documentation we can, in theory, get a bunch of members to just start writing code and have a committee approve/fix/adjust as needed (The desire to actually participate and learn seems to be down from what it used to be here but I think we can muster up a few people).

Benefits:
Cross-platform is less of an issue.
More potential participants
    Give a wider ability level a chance to participate.
Use of theSwamps SVN


On topic:
Now that being said; I will still try to create a small project to see if I cant tap-into a COM dll without COM (that info I think I found above) but this task alone will take a lot of time and is only a fraction of step one of our current route.

Can Jeff's wrapper work in the Mac OS X environment (I thought it couldn't--I know *nix doesn't have COM so...)?

If you need me I will be knee deep in that code you call a mess :D
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9484
Re: Extending AutoLisp - Let's start with format
« Reply #11 on: August 15, 2011, 10:35:39 AM »
Has anyone heard of CORBA? I hadn't. It works on Windows and *nix.

Heres a wikipedia link.
http://en.wikipedia.org/wiki/Common_Object_Request_Broker_Architecture


**EDIT:
Okay, I guess that route isn't the best choice.
« Last Edit: August 15, 2011, 10:45:38 AM by Se7en »
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Extending AutoLisp - Let's start with format
« Reply #12 on: August 15, 2011, 10:53:37 AM »
Thanks. That's the point! I don't want to re-invent the wheel, neither do I want to re-invent the square wheel, and I certainly don't want to rip out the hammer in order to invent these wheels! I just wanted to know which direction to follow, perhaps a combination (i.e. ARX where Lisp has no chance, and direct in Lisp where it's possible)? BTW, http://autocad.xarch.at/stdlib/ seems as an old version of such library created directly in ALisp.

As for the extension through ARX/COM/NET, it would probably be better going with C++ for portability at least. Only then we'll need to compile for each Version / OS alternative of course.

About the "mess", I only said it looks like a mess ... but that may be due to me having much more experience in VB/C#/Java/Delphi/Lisp. They're cleaner & more "elegant" languages. It's definitely not to say C++ can't be made "elegant" either, it just usually isn't done that way.

Anyhow, I was throwing out the different options available. Whatever we decide I think we should try to steer as close as possible to CL's functions, it's a quite mature language and has come a long way through many revisions. Also it's one of the main lisps used, thus making an ALisper much more able to port his knowledge to other branches as well.

Glad of the help! If you can give me some hints on how to go about the C++ stuff I'd be willing to get stuck into that side myself as well.

Anyhow, this is an example of some of the libraries I've done previously: http://caddons.svn.sourceforge.net/viewvc/caddons/Libraries/Lists.LSP?revision=56&view=markup Though many of those use vl functions which I'm unsure if they work on Mac (or BC in Wine on Linux).
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

John Kaul (Se7en)

  • Administrator
  • Needs a day job
  • Posts: 9484
Re: Extending AutoLisp - Let's start with format
« Reply #13 on: August 15, 2011, 11:14:02 AM »
Yes, that is Reni's std library I was referring to. It is highly coupled (relies on itself a lot).

C++ is going to be a big problem. We need a way for the two languages to talk to each other. COM is used in Windows but COM doesn't exist in *nix. We would need to incorporate an IPC mechanism (interprocess communications [IPC]) of some sort (CORBA is one of many D-BUS, QtDBUS, ICE are others). As far cross platform code goes, Qt is the best bet (using D-BUS--QtDBUS to be specific-) but D-BUS/QtDBUS isn't supported on Windows.

TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Extending AutoLisp - Let's start with format
« Reply #14 on: August 15, 2011, 11:33:11 AM »
Qt is the best bet (using D-BUS--QtDBUS to be specific-) but D-BUS/QtDBUS isn't supported on Windows.
:lmao: So you mean we need to install CygWin to have ACad work on windows! What the... Don't let Adesk hear of that! They might have to divorce from M$!

I wonder if some form of RPC could be used? I know a lot of these inter-operating programs use that instead. As a matter of fact I think it's close to what Qt does in any case. Though I can't see a way of linking to such from the ALisp side, perhaps a small ARX just to allow that might do the trick. Though in such case it might even be possible to write a OS specific connector seeing as each ARX needs separate compiling anyway. So all that's really needed is the OS specific linking mechanism.
« Last Edit: August 15, 2011, 11:36:12 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.