Evaluating string encoded code with Compiler

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Evaluating string encoded code with Compiler

Costas Menico-2
I have a need to evaluate code where code is represented as a string.

| user |
user:=123.
myCode := '^user'.
Compiler evaluate: myCode for: self logged: false.

When I evaluate this from a workspace, this returns nil instead of
123. I am assuming the evaluation context must be passed to the
Compiler to make the variable 'user' visible.
How is this done?

Also how can I get an object to the current workspace and the list of
temporary variables?  

Thanks,

Costas


Reply | Threaded
Open this post in threaded view
|

Re: Evaluating string encoded code with Compiler

Ian Bartholomew-2
Costas,

> I have a need to evaluate code where code is represented as a string.
>
> | user |
> user:=123.
> myCode := '^user'.
> Compiler evaluate: myCode for: self logged: false.
>
> When I evaluate this from a workspace, this returns nil instead of
> 123. I am assuming the evaluation context must be passed to the
> Compiler to make the variable 'user' visible.
> How is this done?

I don't think you can, workspaces are always evaluated with a receiver of
nil. Also, when you evaluate the above in a workspace the "user" variable
would only be created (speaking theoretically) as part of the compilation
process of the complete statement (all four lines). I wouldn't think you can
have a reference _within those four lines to something that will only be
created as a _result of its own compilation.

There are, that I can see anyway, three reasonable things you can do
(below). There might be other ways, maybe involving blocks or dummy classes
to give you a context in which you could evealuate the statement but I would
think they would be a lot more complicated than these solutions.

Evaluate the lot (a bit pointless really)-

myCode := '| user |
user:=123.
^user'.
Compiler
    evaluate: myCode
    for: self
    logged: false.

Insert into the compiled expression (only works when user is a simple
object) -

| user |
user:=123.
myCode := '^', user printString.
Compiler
    evaluate: myCode
    for: self
    logged: false.

Use the same technique that OA use for workspaces (works in all cases) -

| user pool |
user := 123.
myCode := '^user'.
pool := PoolDictionary new at: 'user' put: user; yourself.
Compiler
    evaluate: myCode
    for: self
    evaluationPools: (Array with: pool)
    logged: false

> Also how can I get an object to the current workspace and the list of
> temporary variables?

You'll have to expand on what you mean for both of those questions.

Ian


Reply | Threaded
Open this post in threaded view
|

Re: Evaluating string encoded code with Compiler

Costas Menico-2
"Ian Bartholomew" <[hidden email]> wrote:

>Costas,
>
>> I have a need to evaluate code where code is represented as a string.
>>
>> | user |
>> user:=123.
>> myCode := '^user'.
>> Compiler evaluate: myCode for: self logged: false.
>>
>> When I evaluate this from a workspace, this returns nil instead of
>> 123. I am assuming the evaluation context must be passed to the
>> Compiler to make the variable 'user' visible.
>> How is this done?
>
>I don't think you can, workspaces are always evaluated with a receiver of
>nil. Also, when you evaluate the above in a workspace the "user" variable
>would only be created (speaking theoretically) as part of the compilation
>process of the complete statement (all four lines). I wouldn't think you can
>have a reference _within those four lines to something that will only be
>created as a _result of its own compilation.
>
>There are, that I can see anyway, three reasonable things you can do
>(below). There might be other ways, maybe involving blocks or dummy classes
>to give you a context in which you could evealuate the statement but I would
>think they would be a lot more complicated than these solutions.
>
>Evaluate the lot (a bit pointless really)-
>
>myCode := '| user |
>user:=123.
>^user'.
>Compiler
>    evaluate: myCode
>    for: self
>    logged: false.
>
>Insert into the compiled expression (only works when user is a simple
>object) -
>
>| user |
>user:=123.
>myCode := '^', user printString.
>Compiler
>    evaluate: myCode
>    for: self
>    logged: false.
>
>Use the same technique that OA use for workspaces (works in all cases) -
>
>| user pool |
>user := 123.
>myCode := '^user'.
>pool := PoolDictionary new at: 'user' put: user; yourself.
>Compiler
>    evaluate: myCode
>    for: self
>    evaluationPools: (Array with: pool)
>    logged: false
>
>> Also how can I get an object to the current workspace and the list of
>> temporary variables?
>
>You'll have to expand on what you mean for both of those questions.
>

I want to create a method that can create an OrderedCollection from a
string as a shortcut to the normal way. Eg.

user:='somebody'.
password:='secret'.
arr:='user. password. Date today. #something. #(1 2).' asValues.

I thought it would be a breeze. So, naively, I wrote the following:

String>>asValues
| rs collection |
rs:=ReadStream on: self.
collection := OrderedCollection new.
[rs atEnd] whileFalse: [
        collection add: (Compiler evaluate:  (rs upTo: $.)
                logged: false).
].
^collection

Evaluating the above you get:
an OrderedCollection(nil nil Tuesday, December 26, 2000, #something
#(1 2).)

which is not what I want.

Basically the logic is to parse the string for a '.' , evaluate
whatever you get and stuff it into a collection. It works for literals
but not for temporary variables which now makes sense. Of course it
would work for anything provided you have a reference to the object
that holds the variables.

I can create an evaluationPool and pass it as a parameter, but then
that defeats the purpose of the shortcut. So I was hoping that if I
could get a reference to the temporary variables of the calling method
(i.e. evaluate in a different context) then it would work. I know some
other languages have this ability (Tcl/Tk) to do this which really is
a very powerful capability.

Costas


Reply | Threaded
Open this post in threaded view
|

Re: Evaluating string encoded code with Compiler

Ian Bartholomew
Costas,

> I want to create a method that can create an OrderedCollection from a
> string as a shortcut to the normal way. Eg.
>
> user:='somebody'.
> password:='secret'.
> arr:='user. password. Date today. #something. #(1 2).' asValues.

Yes, I guessed it was something to do with the other thread that you have
been taking part in. I thought that you would probably find that a general
purpose shortcut for creating arrays might be bit more difficult than it
first appears - I wasn't sure though, there are some clever Smalltalkers
about.

user:='somebody'.
password:='secret'.
arr := OrderedCollection new
    add: user;
    add: password;
    addAll: #(##(Date today) #something #(1 2));
    yourself

would be my best (shortest) solution and, I have to say, just as easy and
clear to read IMHO, especially as I would probably not even bother with
using the #addAll.

Ian

PS. If you want to compile the code today but run it tomorrow than using the
##(Date today) bit in my code would be an error as well


Reply | Threaded
Open this post in threaded view
|

Re: Evaluating string encoded code with Compiler

Costas Menico
On Tue, 26 Dec 2000 16:15:46 -0000, "Ian Bartholomew"
<[hidden email]> wrote:

>Costas,
>
>> I want to create a method that can create an OrderedCollection from a
>> string as a shortcut to the normal way. Eg.
>>
>> user:='somebody'.
>> password:='secret'.
>> arr:='user. password. Date today. #something. #(1 2).' asValues.
>
>Yes, I guessed it was something to do with the other thread that you have
>been taking part in. I thought that you would probably find that a general
>purpose shortcut for creating arrays might be bit more difficult than it
>first appears - I wasn't sure though, there are some clever Smalltalkers
>about.

Yes, I am kind of persistent with some things but I learned a lot...

Regards,

Costas


Reply | Threaded
Open this post in threaded view
|

Re: Evaluating string encoded code with Compiler

David Simmons
In reply to this post by Costas Menico-2
Costas,

You might want to consider the following ideas. I've chosen only mechanisms
that could be added to any Smalltalk via messages.


    |c|

    c := OrderedCollection new.
    c << user << password << Date today << #something << #(1 2).
   ^c asStringList. "Or #storeString"

    "asStringList --> Returns a <String> composed of each
     item converted to a string representation and then concatenated
     and delimited (by default) with a $; . <#asStringList: aDelimiter>
     is also an option if $; is not appropriate."

    "SomeName;SomePassword;Tuesday, December 26, 2000;#something;#(1 2)"

<!-- -->

    |c|

    c := aStringCollection asList. "Does the reverse of #asStringList"

<!-- -->

    If Dolphin supports the Smalltalk message #storeString or some
    equivalent then you already have a built in behavior for simple
    conversion of objects into a source form. You can use the compiler
    to un-encode it, as in:

    aSourceForm := c storeString.
    ...
    c := Compiler evaluate: aSourceForm.

    "Or if it has #storeOn:"
    c storeOn: aStream.
    ...
    c := Compiler evaluate: aStringContainingTheStreamsContents.

<!-- -->

    You might also want to consider writing some <MyEncoder> class
    that can take a <OrderedCollection> and return a <String>, or
    take a <String> and return an <OrderedCollection>. Your encoder
    class would then encapsulate all the specifics and would not
    necessarily need to involve the compiler.

-- Dave Simmons [www.qks.com / www.smallscript.com]
  "Effectively solving a problem begins with how you express it."

"Costas Menico" <[hidden email]> wrote in message
news:[hidden email]...

> "Ian Bartholomew" <[hidden email]> wrote:
>
> >Costas,
> >
> >> I have a need to evaluate code where code is represented as a string.
> >>
> >> | user |
> >> user:=123.
> >> myCode := '^user'.
> >> Compiler evaluate: myCode for: self logged: false.
> >>
> >> When I evaluate this from a workspace, this returns nil instead of
> >> 123. I am assuming the evaluation context must be passed to the
> >> Compiler to make the variable 'user' visible.
> >> How is this done?
> >
> >I don't think you can, workspaces are always evaluated with a receiver of
> >nil. Also, when you evaluate the above in a workspace the "user" variable
> >would only be created (speaking theoretically) as part of the compilation
> >process of the complete statement (all four lines). I wouldn't think you
can
> >have a reference _within those four lines to something that will only be
> >created as a _result of its own compilation.
> >
> >There are, that I can see anyway, three reasonable things you can do
> >(below). There might be other ways, maybe involving blocks or dummy
classes
> >to give you a context in which you could evealuate the statement but I
would

> >think they would be a lot more complicated than these solutions.
> >
> >Evaluate the lot (a bit pointless really)-
> >
> >myCode := '| user |
> >user:=123.
> >^user'.
> >Compiler
> >    evaluate: myCode
> >    for: self
> >    logged: false.
> >
> >Insert into the compiled expression (only works when user is a simple
> >object) -
> >
> >| user |
> >user:=123.
> >myCode := '^', user printString.
> >Compiler
> >    evaluate: myCode
> >    for: self
> >    logged: false.
> >
> >Use the same technique that OA use for workspaces (works in all cases) -
> >
> >| user pool |
> >user := 123.
> >myCode := '^user'.
> >pool := PoolDictionary new at: 'user' put: user; yourself.
> >Compiler
> >    evaluate: myCode
> >    for: self
> >    evaluationPools: (Array with: pool)
> >    logged: false
> >
> >> Also how can I get an object to the current workspace and the list of
> >> temporary variables?
> >
> >You'll have to expand on what you mean for both of those questions.
> >
>
> I want to create a method that can create an OrderedCollection from a
> string as a shortcut to the normal way. Eg.
>
> user:='somebody'.
> password:='secret'.
> arr:='user. password. Date today. #something. #(1 2).' asValues.
>
> I thought it would be a breeze. So, naively, I wrote the following:
>
> String>>asValues
> | rs collection |
> rs:=ReadStream on: self.
> collection := OrderedCollection new.
> [rs atEnd] whileFalse: [
> collection add: (Compiler evaluate:  (rs upTo: $.)
> logged: false).
> ].
> ^collection
>
> Evaluating the above you get:
> an OrderedCollection(nil nil Tuesday, December 26, 2000, #something
> #(1 2).)
>
> which is not what I want.
>
> Basically the logic is to parse the string for a '.' , evaluate
> whatever you get and stuff it into a collection. It works for literals
> but not for temporary variables which now makes sense. Of course it
> would work for anything provided you have a reference to the object
> that holds the variables.
>
> I can create an evaluationPool and pass it as a parameter, but then
> that defeats the purpose of the shortcut. So I was hoping that if I
> could get a reference to the temporary variables of the calling method
> (i.e. evaluate in a different context) then it would work. I know some
> other languages have this ability (Tcl/Tk) to do this which really is
> a very powerful capability.
>
> Costas
>


Reply | Threaded
Open this post in threaded view
|

Re: Evaluating string encoded code with Compiler

Ian Bartholomew
In reply to this post by Costas Menico
Costas,

Prompted by David's message, why not

user:='somebody'.
password:='secret'.
x := OrderedCollection new << user << password << Date today << #something
<< #(1 2).

which works in Dolphin after the implementation of one method

Collection>><< something
    self add: something.
    ^self

Don't know about other Smalltalks or even that it will work consistenly in
Dolphin.  Is Dolphin guaranteed to do the above left to right?

You can change the symbol used but there are a restrictions due to Dolphin's
compiler, you can't use the more obvious + for example.

Ian


Reply | Threaded
Open this post in threaded view
|

Re: Evaluating string encoded code with Compiler

Reinout Heeck
In reply to this post by David Simmons
> > >> I have a need to evaluate code where code is represented as a string.
> > >>
> > >> | user |
> > >> user:=123.
> > >> myCode := '^user'.
> > >> Compiler evaluate: myCode for: self logged: false.
> > >>
> > >> When I evaluate this from a workspace, this returns nil instead of
> > >> 123. I am assuming the evaluation context must be passed to the
> > >> Compiler to make the variable 'user' visible.
> > >> How is this done?


In VisualWorks it can be accessed as the psuedoVariable named
thisContext.

The following workspace code will evaluate to 123:

| user myCode |
myCode := '^user'.
user:=123.
Compiler new
        evaluate: myCode
        in: thisContext
        receiver: nil
        notifying: nil
        ifFail: nil  


What are you writing, a new debugger?
Why else would do you need this? (all kinds of alarm bells are ringing:
there must be a prettier and *safer* way to do what you need)



Cheers!

Reinout
-------


Reply | Threaded
Open this post in threaded view
|

Re: Evaluating string encoded code with Compiler

Costas Menico-2
Reinout Heeck <[hidden email]> wrote:

>
>> > >> I have a need to evaluate code where code is represented as a string.
>> > >>
>> > >> | user |
>> > >> user:=123.
>> > >> myCode := '^user'.
>> > >> Compiler evaluate: myCode for: self logged: false.
>> > >>
>> > >> When I evaluate this from a workspace, this returns nil instead of
>> > >> 123. I am assuming the evaluation context must be passed to the
>> > >> Compiler to make the variable 'user' visible.
>> > >> How is this done?
>
>
>In VisualWorks it can be accessed as the psuedoVariable named
>thisContext.
>
>The following workspace code will evaluate to 123:
>
>| user myCode |
>myCode := '^user'.
>user:=123.
>Compiler new
> evaluate: myCode
> in: thisContext
> receiver: nil
> notifying: nil
> ifFail: nil  
>
>
>What are you writing, a new debugger?
>Why else would do you need this? (all kinds of alarm bells are ringing:
>there must be a prettier and *safer* way to do what you need)

This is exactly what I am looking for. A thisContext type of variable
or message. I am not sure if Dolphin supports this. They may in an
indirect way. They have a for: instead of in: but that is used to pass
an object as the context.


Costas