This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: TCL->Scheme



ian@bickiia.earlhall.earlham.edu writes:
> Maciej Stachowiak writes:
> > I'm glad someone is working on this. Are you doing this specifically
> > for Guile, or trying to be portable to any RnRS Scheme?
> 
> Right now I'm doing it in SCM, because Simlix supports just SCM and
> Chez Scheme.  Of course, it should be quite easy to port to Guile, but
> I haven't bothered working through those details (I just got the
> partial evaluator to work on my code yesterday).  Mostly the module
> stuff in Similix would need to be ported (to get at slib), and I don't
> understand modules in SCM or Guile so I haven't tried yet.
> 

It's possible to get at slib pretty easily from Guile (although I
don't think the latest version works).

> It should be pretty easy to port to anything else -- Similix supports
> a functional subset of Scheme, so I'm fairly restricted in what I do.
> You can get at all the other stuff, but it's kept separate and defined
> differently -- which makes it pretty clear what would need to be
> ported.  Also it seems that using more exotic procedures (like (eval
> (string->symbol...))) might keep the evaluator from working as well,
> so it would be judicious for me to avoid them.  However, Simlix would
> need to be ported for it to be very useful (as a straight interpreter
> there are some wild inefficiencies put in to keep it functional --
> these should disapear during the partial evaluation stage, but leave
> the interpreter inefficient).
> 
> As it is, I've implemented a whole lot of little things which must
> exist in other places already (like streaming over a string) but which 
> may work differently with different implementations.  This should make 
> it even more portable.  (I've reimplemented some things to do things
> in a more functional fashion)
> 

Hmm, Guile already has string ports (call-with-input-string,
call-with-output-string), as do many other implementations, if that is
what you mean.

> > There were Gdb patches available, as Jim mentioned a while ago, but I
> > am not sure they are up to date.
> 
> Hmmmm... does anyone know of up-to-date archives of the list?  The
> ones at www.red-bean.com only go up to early August.  I didn't notice
> anything about gdb when I was browsing through them (though maybe I
> missed it).
> 

They seem to not have updated since then. Jim?

> [code examples]
> > ;; then insert in generated code:
> > (access-string-variable "*some-variable*)
> > ;; however, this expands at macro-expansion time, not runtime, which
> > ;; is a shortcoming for some cases in Tcl.
> 
> Yeah, macros wouldn't work on a few levels.  Does the REPL loop use
> plain evals?  (I suppose the "E" would stand for "eval", answering my
> own questions... but I was thinking there might be some deeper
> [structurally] manner of getting at that stuff)
> 

The REPL loop evals, yes. The original intended Guile formalism was
for translators to only replace `read', though, not the whole REPL -
the translator's reader would return Scheme forms in list
representation to be eval'd as appropriate by the REPL.

> > > How can I define a variable based on a string?  E.g., if the TCL
> > > wishes to export some procedure, how can I put that procedure's name
> > > in the global namespace?
> > 
> > Use the same hacks as above in combination with `define'.
> 
> So, if I do something like this:
> 
> (eval (cons (list 'define (string->symbol "mytclproc"))
> 	    (tcl-procedure->lambda tcl-context "mytclproc")))
> 

I'd just have something that would return 
(list 'define (string->symbol "mytclproc")
	(tcl-procedure->lambda tcl-context "mytclproc"))

Actually, I don't really understand the latter part - I'd expect
something more like 

`(define ,@(cons (tcl-string->symbol procname)
		 (map tcl-string->symbol (tcl-string->list arglist)))
   ,@(tcl-string->code procbody))


Where tcl-string->symbol is just string->symbol, assuming Tcl strings
are implemented as Scheme strings, tcl-string->list uses tcl's list
conversion rules and returns a list of strings, and tcl-string->code
recursively does the same string ==> scheme s-expression conversion as
your translator as a whole, recursively on the given string taken as a
list. Maybe a more accurate expression for this idea would be

(map tcl-statement->s-expression (tcl-string->list procbody))

which better expresses the idea that you treat the body of a tcl
"proc" as a list of statements, 

which expresses the idea of treating the body as a list of statements,
each of which is recursively turned into an s-expression.

> It should work?  How can I get it defined in the global scope?
> 

I think you should just write a replacement for `read' and leave it up
to the repl to put things in the global scope.

> I'm not trying to merge any of the local TCL stuff with Scheme -- the
> mixing of the languages at anything less that the global scope seems
> unnecessary.

Probably true.

> 
> [tcl type problems]
> > I don't think there is a better way. Note that you also need to
> > specify the return type unless it is possible to magically convert to
> > strings in a canonical way.
> 
> It should be possible to make a canonical form -- most Scheme data can
> be converted into some sort of TCL string, and the Scheme types are
> rich enough to figure out the method of conversion automatically.
> Anything which can't be converted into a string is going to be
> meaningless to a TCL program anyhow.  Oh.  Except if it passes that
> same value off to another Scheme procedure.  Hmm... I'll have to think
> about that.  There's also messy things like the fact that Scheme ports
> aren't necessarily named, where TCL channels are always named.
> Hmm... I guess it was worse than I thought.  Darn.

There's also the fact that a Scheme list has to be recursively
subconverted or whatever.

> 
> > > So far the translation seems like it's going fairly well -- I'm using
> > > a TCL interpreter written in Scheme, then applying a partial evaluator
> > > (Similix
> > > http://www.diku.dk/research-groups/topps/activities/similix.html).  I
> > > don't think there's really any other reasonable way to translate TCL,
> > > it being so context sensitive. 
> > 
> > I don't know if this will precisely reproduce semantics. There is
> > actually real Tcl code out there that depends on accessing a variable
> > through a name determined by accessing another variable (though I can
> > no longer remember the hairy syntax for this).
> 
> set a green
> set x a
> set $x blue
> puts $a
>   ==> blue
> 
> It actually isn't too hairy -- it falls right out of TCL syntax.  It's 
> just like LOGO, really:
> 
> MAKE "a "green
> MAKE "x "a
> MAKE :x "blue
> PRINT :a
>   ==> blue
> 
> There's some validity to the way TCL does this, theoretically.
> Assignment isn't a special form, much unlike most languages.
> 
> Now, expr is ugly (with it's double parsing), and lists are ugly too
> (with their double scanning).  Those feel like kludges in TCL -- the
> assignment thing is actually fairly elegant (IMHO).  OTOH, I haven't
> actually ever chosen to program anything in TCL :-)  (Hmm... I guess
> this means that necessity sometimes *isn't* the mother of invention?)
> 
> However, this stuff shouldn't be a problem.  While I still haven't
> implemented much of TCL, this works fine already.



> TCL is meant to be interpreted, which is fine, because I'm
> interpreting it.  The magic is all in the partial evaluator (and it
> isn't even all that magical -- just rigorous).  The partial evaluator
> preserves semantics (for it to do anything else is a bug), so even
> after translation this stuff should work.  *However*, some TCL code
> could translate very poorly, leaving it essentially interpreted.  The
> same goes for byte-code compiling (I imagine they use something
> equivalent to partial evaluational, just not as rigorous).
> 

I am impressed with how much your translator manages to handle. Are
you willing/able to post code somewhere? Maybe I can try some of my
extra-hairy old tcl code from the bad old days and see how it does.

Another interesting problem is how to deal with the fact that arrays
are not first-class in tcl.

> For instance:
> 
> set input [read stdin 1]   # get user input
> set block "puts \"you answered "
> if {"$input" == "y"} {
>     append block "yes\""  # paste 'yes"' onto the end of block
> } else {
>     append block "no\""
> }
> while {true} $block
> 
> (if you enter "y", it prints out "you answered yes" forever,
> anything else prints "you answered no")
> 
> This is nearly uncompilable but is perfectly legal TCL.  Heck, maybe
> people even write like this :-)  It's actually reminiscent of
> first-class functions.  Nevertheless, it's why direct translation
> doesn't seem like it could work.
> 

Yes, there always needs to be an interpretive fallback for really
hairy cases, I imagine.

 - Maciej Stachowiak