I've started a new test file t/pmc/namespace.t that summarizes some of
the current possibilities of namespace manipulation with Parrot.
Please have a look at the supported syntax constructs. Are these
sufficient for HLL writers?
leo
PS more tests welcome
> t/pmc/namespace.t
> Please have a look at the supported syntax constructs. Are these
> sufficient for HLL writers?
Some more thoughts WRT namespaces.
We can define a namespace, where a function or method is stored:
.namespace ["Foo"]
.sub bar
...
This does effectively (during bytecode loading)
store_global "Foo", "bar", pmc_of_sub_bar
where the C<pmc_of_sub_bar> is living in the constant table.
The general way (and the only one, if the function is in another
bytecode segment), to call the function, is:
$P0 = find_global "Foo", "bar"
$P0()
Ok so far.
But what happens, if the PIR file contains just a plain
bar()
The implementation looks into the current namespace and then in other
namespaces present in the compiled source file, which seems to be quite
wrong to me. Below is a test program [1] that shows how it's working
now.
The opcode to get at the sub "bar" is:
set_p_pc $P0, "bar"
where the symbol "bar" (the PMC constant of the sub) is located in the
source file.
The C<bar()> shorthand call syntax could now look into the current
namespace only. But that seems to restricted to me - or it would make
the shortcut almost useless.
I think that the C<bar()> shortcut should emit a new opcode:
$P0 = find_name "bar"
or maybe:
$P0 = HLL."find_name"("bar") # HLL := a Perl6, Python, ... PMC
The C<find_name> opcode could now look into the current lexicals, the
current namespace aka package, the globals, and finally into the
builtins in that order.
Further: to be able to search the current package namespace, the
interpreter has to know, in which namespace it's currently executing.
This is also needed for MMD function search. To achieve that, all
subroutines would need to remember their namespace and when calling the
sub, that namespace could be placed into the interpreter context.
Comments very welcome,
leo
[1]
$ cat s.imc
.namespace ["Main"] # try it with and w/o this line
.sub main @MAIN
print "calling foo\n"
foo()
print "calling Foo::foo\n"
$P0 = find_global "Foo", "foo"
$P0()
print "calling baz\n"
baz()
.end
.sub foo
print " foo\n"
bar()
.end
.sub bar
print " bar\n"
.end
.sub fie
print " fie\n"
.end
.namespace ["Foo"]
.sub foo
print " Foo::foo\n"
bar()
fie()
.end
.sub bar
print " Foo::bar\n"
.end
.sub baz
print " Foo::baz\n"
.end
$ parrot s.imc
calling foo
foo
bar
calling Foo::foo
Foo::foo
bar # or Foo::bar
fie
calling baz
Foo::baz
>But what happens, if the PIR file contains just a plain
>
> bar()
Since PIR behaviour is ours to define, it can do whatever we want.
I'm inclined to rule that a plain
bar()
is equivalent to:
current_namespace::bar()
and as such the PIR compiler should look up the function by name in
the current namespace and then invoke it.
>The implementation looks into the current namespace and then in other
>namespaces present in the compiled source file, which seems to be quite
>wrong to me.
Yeah, this isn't the right thing.
Since invoking a sub in the current file's also useful and something
we do (I'm making heavy use of it. It's nice :) I can see having
alternate syntax for it. Perhaps:
:bar()
looks for the bar sub in the current namespace in the current file
and invokes it, skipping any sort of by-name lookup or runtime sub
overriding.
(And yeah, I suggest this even though it'd mean rewriting some of my
compiler's codegen code)
Any semantics past these (simple lookup by name, and simple
compiletime lookup) should be delegated to the individual language
compilers, and they can emit code to do whatever oddball things they
may need to do, though I'm not sure there's a whole lot more that'd
need to be done for most languages. (Especially since namespaces are
supposed to be lexically and dynamically overridable, as well as
layered, but that's all a separate thing)
--
Dan
--------------------------------------it's like this-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk
> Since PIR behaviour is ours to define, it can do whatever we want.
> I'm inclined to rule that a plain
> bar()
> is equivalent to:
> current_namespace::bar()
> and as such the PIR compiler should look up the function by name in
> the current namespace and then invoke it.
Ok. So this "bar" is overridable by putting another Sub object into the
"bar" slot of the namespace, I presume...
> Since invoking a sub in the current file's also useful and something
> we do (I'm making heavy use of it. It's nice :) I can see having
> alternate syntax for it. Perhaps:
> :bar()
> looks for the bar sub in the current namespace in the current file
> and invokes it, skipping any sort of by-name lookup or runtime sub
> overriding.
... while this one would reflect the current static behavior of subs
defined in the current namespace, which translates just to a constant
table lookup:
set_p_pc Px, the_sub_PMC_named_bar
> (And yeah, I suggest this even though it'd mean rewriting some of my
> compiler's codegen code)
> Any semantics past these (simple lookup by name, and simple
> compiletime lookup) should be delegated to the individual language
> compilers, and they can emit code to do whatever oddball things they
> may need to do, though I'm not sure there's a whole lot more that'd
> need to be done for most languages. (Especially since namespaces are
> supposed to be lexically and dynamically overridable, as well as
> layered, but that's all a separate thing)
Currently a C< bar() > function call shortcut emits:
Px = find_name "bar"
when "bar" isn't known in the current namespace, which looks into
lexicals, globals, and builtins in that order.
> -- Dan
leo