This is the mail archive of the
kawa@sources.redhat.com
mailing list for the Kawa project.
Re: Handling Bindings for Perl variables
"Bradley M. Kuhn" <bkuhn@ebb.org> writes:
> I agree, that is definitely needed, particular to handle ties. However,
> there probably needs to be another layer of indirection as well to handle
> things like glob assignment:
> *a = *b
> will cause $a, @a, %a to be aliases for $b, @b, and %b, respectively.
>
> So, I was thinking that there would be a subclass of Binding, called a Glob,
> that would contain Binding entries for each type of variable that can be
> held in that Glob. This would make operations on Globs easier.
It is difficult for me to say, since I have a hard time figuring out
from the Camel book (2nd edition) exactly what a "typeglob" is and
what the valid operations on it are.
> However, am I overthinking this? Should I instead just implement Glob
> operations like "*a = *b" by generating code to find all these entries and
> put the right Constraints in place?
That seems a better alternative, but I'd have to understand better
what typelobs are and how they are used. Just the "*a = *b" operation
is certainly easy enough to do as three seprate operations.
> Also, on another matter, I didn't see a way to easily use existing Bindings.
> I looked at Binding2, as that seemed the closest to what I'd have to do for
> Perl variables.
No. If we use seprate Binding objects for scalar, array, and hash
variables, I don't see any reason for needing Binding2 - especially
since Binding2 is a hack that I would like to remove.
> Could I perhaps help generalize what is there?
Why do you need to? At least for scalar variables, can't you
use Binding as is? Array/hash variables are trickier, but I would
still use a Binding for them, but perhaps with special constraints.
> This sounds like a good idea. I am curious, though, how to handle both
> lexicals as well as globals this way.
Lexicals are handled differently, not using the Environment/package
framework. In most case, a lexical variable would be a single Java
local variable. A Binding may be created if you "take its address"
(make a reference to it) - but I don't know if Perl lets you create
a reference to a lexical. In any case, Kawa handles lexical variables
(and closures) automatically, normally without creating a Binding.
> Should each scope have an Environment, too?
No. Each scope has a compile-time ScopeExp, but not a run-time
Environment.
> Should I just declare lexicals as Binding objects in the given scope?
No.
> If you can point me in the right direction on how to use Bindings to handle
> globals and Lexicals, I'd appreciate it.
You could try a trivial Scheme program and see how Kawa
compiles it. For example:
sub foo {
my $a = shift;
my $b = shift;
}
would be similar to:
(define (&foo . @args)
(define $a (shift @args))
(define $b (shift @args))
...)
The function body is handled (for Scheme) by Translator rewrite_body.
The idea is you create a LetExp for the function body. For each
lexical name defined by "my", add a new Declaration to the LetExp.
You can see how this is done by kawa.standard.define. For Scheme,
the conversion from s-exprs to Expresion forms is two pass: The
first pass is "scanning" (scan_body, scan_form, scanForDefinitions),
which accumulates definitions; the second pass calls rewrite.
The passes are intertwinded to deal with recursive internal define-s
in Scheme; you may not have to deal with that in Perl. The basic
idea is that a sub-class of Parser (Translator for Scheme and Lisp)
keep track of source state, and maintains a stack of ScopeExps for
the lexcial scope; any lexical definictions are added as Declarations
in the current ScopeExp (typically a LetExp). Thus "my $a = ...;"
creates a new Declaration in the current scope, which has name "$a".
I am in the middle of changing Kawa so all variables references get
bound to Declaration. If there is no lexical Declaration, one is
created that has the IS_UNKNOWN flag. So note there will be some
changes here in the next few days (I hope - it could easily take longer!).
> For global variables, one idea that I had for was to create an superclass
> for all Perl modules:
>
> interface PerlModule {
> Environment moduleEnv;
Why? Is there anything in a Perl module *except* an Environment?
If not, just use an Environment as is. Otherwise, use inheritance:
class PerlModule extends Environment.
> Or something like that. That way, it would be easy for a Java programmer or
> even Scheme programmers to get at Perl variables in a module.
It is easy as it is. To get the Binding for "$a" in package "Foo", do:
Environment foo = Perl.findPackage("Foo");
... foo.getBinding("$a") ...
Consider this code:
package Foo;
sub foo { my $b = $#list; return $a + $b; }
I think it should compiled into something like:
// These all get put in <clinit>:
static Environment Foo = Perl.findPackage("Foo");
static Binding $Dla = Foo.getBinding("$a");
static Binding $Atlist = Foo.getBinding("%list");
static Object foo () {
PerlScalar $Dlb = Perl.getArrayLength($Atlist)
// or perhaps: Perl.getArrayLength($Atlist.get());
return Perl.add($Dla.get(), $Dlb);
}
The names $Dla, $Dlb, $Atlist are "mangled" from $a, $b, @list.
(See Compilation.mabgleName.)
Note that the hash table lookups (findPackage, getBinding) are
all done a class load time, not run time. At run time you
essentially call the appropriate Constraint methods.
--
--Per Bothner
per@bothner.com http://www.bothner.com/~per/