Author Topic: Eval/Read/Apply  (Read 3313 times)

0 Members and 1 Guest are viewing this topic.

QuestionEverything

  • Guest
Eval/Read/Apply
« on: October 25, 2016, 08:22:27 AM »
This is some mind-stretching thread.
How can you re-write the following:
Code: [Select]
(command "_.CIRCLE"  "_non"  (getpoint)  50)So it can be evaluated.

I only figured out these:
Code: [Select]
(apply 'command (list "_.CIRCLE"  "_non"  (getpoint)  50)) ; works
(eval '(command "_.CIRCLE"  "_non"  (getpoint)  50)) ; works

I also tried to evaluate it as a string, but it doesn't work:
Code: [Select]
(eval (read "command '_.CIRCLE '_non (getpoint) 50"))
Obviously this thread is not about entmake(x)/vla-Add, but just to evaluate something (list/string/ ...? ) as a command call.
I just wanted to know what more options are out there.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Eval/Read/Apply
« Reply #1 on: October 25, 2016, 11:31:06 AM »
I don't have time to play but have a look at these 2 functions form my toolbox.

Code: [Select]
(defun _Catch ( func lst / catch_result )
    ;; (_Catch '/ '(4 2)) >> 4
    ;; (_Catch '/ '(1 0)) >> nil
    (if (null (vl-catch-all-error-p (setq catch_result (vl-catch-all-apply func lst))))
        catch_result
    )
)

(defun _Eval ( quoted_statement / eval_result )
    ;;  (_Eval '(/ 4 2)) >> 4
    ;;  (_Eval '(/ 1 0)) >> nil
    (if
        (null
            (vl-catch-all-error-p
                (setq eval_result
                    (vl-catch-all-apply 'eval (list quoted_statement))
                )
            )
        )
        eval_result
    )
)

I generally use _Catch (it's faster) but for larger constructs _Eval sometimes makes more sense.

Regarding use in (command ...) constructs also read up on vl-cmdf.

Cheers.
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

QuestionEverything

  • Guest
Re: Eval/Read/Apply
« Reply #2 on: October 25, 2016, 02:35:17 PM »
MP, these functions look very handy, thanks!
I've did some tests and only managed to work this out:
Code: [Select]
(_Eval '(command "_.CIRCLE"  "_non"  (getpoint)  50)) ; worksI'm wondering is there a way to evaluate strings, since so far it seems that this works only with lists.
From help about eval:
Quote
Signature
(eval expr)
expr
Type: Integer, Real, String, List, T, nil, ads_name, Symbol
The expression to be evaluated.
Return Values
Type: Integer, Real, String, List, T, nil, ads_name, Symbol
The result of the expression, after evaluation.

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: Eval/Read/Apply
« Reply #3 on: October 25, 2016, 02:46:36 PM »
I'm wondering is there a way to evaluate strings, since so far it seems that this works only with lists.

Evaluating a string:
Code - Auto/Visual Lisp: [Select]
  1. _$ (eval "string")
  2. "string"

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Eval/Read/Apply
« Reply #4 on: October 25, 2016, 02:57:24 PM »
Sorry for the abbreviated response but --

You'd be better served by taking this approach IMO:

Code: [Select]
(if (setq point (getpoint))
    (command "_.CIRCLE" "_non" point 50))
)

While using _Eval will technically work as you've highlighted it's not really benefitting you.

I use _Catch and _Eval more typically in situations more like this contrived example:

Code: [Select]
(and
    (setq doc (vla-get-activedocument (vlax-get-acad-object)))
    (setq blocks (vla-get-blocks doc))
    (setq block_def (_Catch 'vla-item (list blocks "trump_is_a_tard")))
    (progn
        (setq target nil)
        (_Eval
           '(vlax-for object block_def
                (and
                    (wcmatch (vla-get-objectname object) "AcDbText,AcDbMText")
                    (wcmatch (strcase (vla-get-textstring object) t) "*such a nasty woman*")
                    (setq target object)
                    (exit)
                )
            )
        )
        target
    )   
    (vla-put-textstring target "She is certainly flawed but you're an asshat.")
    ...
)

To use _Eval with strings you might do something like this (tho this is academic rather than actually practical):

Code: [Select]
(_Eval '(eval (read "(/ 4 2)")))
Gotta go, sorry.

Edit: Fixed numerous typos.
« Last Edit: October 25, 2016, 03:02:18 PM by MP »
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

QuestionEverything

  • Guest
Re: Eval/Read/Apply
« Reply #5 on: October 25, 2016, 03:34:47 PM »
Thanks for the examples MP,
I was curious what exactly happens here:
Code: [Select]
(_Eval
'(vlax-for object block_def
(and
(wcmatch (vla-get-objectname object) "AcDbText,AcDbMText")
(wcmatch (strcase (vla-get-textstring object) t) "*such a nasty woman*")
(setq target object)
(exit)
)
)
)
Does it "error-traps" the whole vlax-for statement, or every single object within vlax-for?
I am familiar with the other examples you mentioned so I ask only for the unknown ones.


I'm wondering is there a way to evaluate strings, since so far it seems that this works only with lists.

Evaluating a string:
Code - Auto/Visual Lisp: [Select]
  1. _$ (eval "string")
  2. "string"
Lee Mac,
I mean why something like this won't work:
Code: [Select]
(eval (read  "command \"" _.CIRCLE "\"  \"" _non "\"  (getpoint)  50"))
(eval '(command \"" _.CIRCLE "\"  \"" _non "\"  (getpoint)  50))
(eval "command \"" _.CIRCLE "\"  \"" _non "\"  (getpoint)  50")

I am trying to figure-out/learn something new, although I'm not sure where this would be useful - maybe to run few lines from an external .lsp file.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Eval/Read/Apply
« Reply #6 on: October 25, 2016, 03:49:12 PM »
What does _Eval's argument signature suggest?
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

QuestionEverything

  • Guest
Re: Eval/Read/Apply
« Reply #7 on: October 25, 2016, 04:41:42 PM »
What does _Eval's argument signature suggest?
It seems that it traps the whole vlax-for statement, sorry but this is new for me and it looks magical.  :-o

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: Eval/Read/Apply
« Reply #8 on: October 25, 2016, 05:14:48 PM »
I mean why something like this won't work:
Code: [Select]
(eval (read  "command \"" _.CIRCLE "\"  \"" _non "\"  (getpoint)  50"))
(eval '(command \"" _.CIRCLE "\"  \"" _non "\"  (getpoint)  50))
(eval "command \"" _.CIRCLE "\"  \"" _non "\"  (getpoint)  50")

Addressing each of your examples in turn:



For your first example:
Code - Auto/Visual Lisp: [Select]
  1. (eval (read  "command \"" _.CIRCLE "\"  \"" _non "\"  (getpoint)  50"))

Given that read accepts only a single string argument and your expression consists of several separate symbols & strings, I will assume you that you actually mean:
Code - Auto/Visual Lisp: [Select]
  1. (eval (read "command \"_.CIRCLE\" \"_non\" (getpoint) 50"))

Since the read function will return the first valid AutoLISP expression found in a string, this will return the command function:
Code - Auto/Visual Lisp: [Select]
  1. _$ (read "command \"_.CIRCLE\" \"_non\" (getpoint) 50")

Which, when evaluated, will yield the function pointer:
Code - Auto/Visual Lisp: [Select]
  1. _$ (eval (read "command \"_.CIRCLE\" \"_non\" (getpoint) 50"))
  2. #<SUBR @000000002b2ed6d8 COMMAND>



For your second example:
Code - Auto/Visual Lisp: [Select]
  1. (eval '(command \"" _.CIRCLE "\"  \"" _non "\"  (getpoint)  50))

Again, this contains invalid syntax, so I'll assume you actually mean:
Code - Auto/Visual Lisp: [Select]
  1. (eval '(command "_.CIRCLE" "_non" (getpoint) 50))

This will evaluate, exhibiting the same behaviour as:
Code - Auto/Visual Lisp: [Select]
  1. (command "_.CIRCLE" "_non" (getpoint) 50)

As eval is simply evaluating the quoted literal expression - see here for more information.



For your third example:
Code - Auto/Visual Lisp: [Select]
  1. (eval "command \"" _.CIRCLE "\"  \"" _non "\"  (getpoint)  50")

Again, this contains invalid syntax as the eval function can only accept a single argument, so I'll assume you mean:
Code - Auto/Visual Lisp: [Select]
  1. (eval "command \"_.CIRCLE\" \"_non\" (getpoint) 50")

Since this is merely a literal string, this will be evaluated to give the same string data:
Code - Auto/Visual Lisp: [Select]
  1. _$ (eval "command \"_.CIRCLE\" \"_non\" (getpoint) 50")
  2. "command \"_.CIRCLE\" \"_non\" (getpoint) 50"



Aside, are you using a code editor (such as the Visual LISP IDE) to write your code?
As if so, the code highlighting present in most code editors would enable you to easily spot the syntax errors described above.

MP

  • Seagull
  • Posts: 17750
  • Have thousands of dwgs to process? Contact me.
Re: Eval/Read/Apply
« Reply #9 on: October 25, 2016, 06:46:24 PM »
It seems that it traps the whole vlax-for statement

It does. :) It will either be stopped via (exit) because a matching object was found -- tripping the error hander -- or it will run thru all objects without finding a match.

sorry but this is new for me and it looks magical.  :-o

It only looks magical for a short while -- enjoy it while it lasts -- in no time you will be pulling rabbits out of the hat, will think back and go 'pffftt'. :)
Engineering Technologist • CAD Automation Practitioner
Automation ▸ Design ▸ Drafting ▸ Document Control ▸ Client
cadanalyst@gmail.comhttp://cadanalyst.slack.comhttp://linkedin.com/in/cadanalyst

QuestionEverything

  • Guest
Re: Eval/Read/Apply
« Reply #10 on: October 26, 2016, 05:07:03 AM »
Aside, are you using a code editor (such as the Visual LISP IDE) to write your code?
As if so, the code highlighting present in most code editors would enable you to easily spot the syntax errors described above.
I use notepad++ for writing, but I use Visual LISP IDE's Console to test every row I am unsure about.
Silly me - these double quotes I used were ment for the strcat function, so I simply forgot that < \" > means < " > character.
I rarely write something in VLIDE so I'm not used to spot syntax errors like this, and even the returns I had in the console about this were confusing.

BTW You are very good at explaining things and thanks to it I added another row to the collection:
Code: [Select]
(eval (read "(command \"_.CIRCLE\" \"_non\" (getpoint) 50)")) ; works
Sometimes I paste some code in VLIDE for "debugging" but mainly to understand what exactly happens in the code (such as MP's (_Eval) example).
The joy didn't left me yet for "this discovery" about this (vl-some) for collection objects.
Thanks MP, Thanks LM ! :)