This is the mail archive of the kawa@sources.redhat.com mailing list for the Kawa project.


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

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/

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