I'm thinking XS thoughts because we're going to need a few external
things at SOME point.... It would be so nice if Perl 6's XS was part of
the language, rather than an external pre-processor.

Something like:

    module somesuch;
    use External (language=>"C");
    sub chdir(string $path //= $ENV{HOME}) is external(returns=>'int');

Then you could extract the C source like so:

    perl -MExternal -e 'extract "chdir"'

Which would generate something along the very vague lines of:

    #include<parrot_external.h>
    /* modulename.c */
    void perlexternal_chdir(parrot_sv *path) {
        char* param_path = parrot_sv_to_char_STAR(path);
        int RETVAL = chdir(param_path);
        parrot_stackpush(parrot_int_to_iv(RETVAL));
    }

The more complex case:

    module getpw;
    use External(language=>"C",PREP=>q{
        #include<pwd.h>
        #include<sys/types.h>});
    
    class uid_t := class real;  # Proposed class alias syntax (see below)
    class gid_t := class real;
    class passwd {
        my string $.pw_name;    # Proposed pseudo-classes "string" and "real"
        my string $.pw_passwd;  # are required to determine how to convert
        my int    $.pw_uid;     # the value to C
        my int    $.pw_gid;
        my string $.pw_gecos;
        my string $.pw_dir;
        my string $.pw_shell;
        method storage { # storage returns a string name of the C type
                         # or a listref to the field names if it's a
                         # struct. If it's a scalar type in C, then
                         # this class must contain a $.internal of the
                         # appropriate Perl pseudo-class type (string,
                         # int or real).
                return
                        [qw{
                                pw_name pw_passwd pw_uid pw_gid
                                pw_gecos pw_dir pw_shell
                        }]
        }
    }
    
    sub getpwuid(uid_t $uid //= $_) is external(returns=>'passwd');

So, to recap:

All types passed to an externally defined function must be classes which
have well defined type behavior.

A subroutine is declared external by using "is external" which takes
argument pairs as parameters.

One of external's parameters is "returns" which take a class name as its
parameter. The function will return an object of the given class.

Classes can be aliased using the C<:=> construct

The following pseudo-classes are defined, which force a parrot-internal
storage and define the mechanism by which the value is translated to
external representation (these are all scalar types):

        int - signed integer value
        real - floating point
        string - A character string
        utf8string - A string which is never converted to ASCII 
        bytes - A string which may contain binary data including nul

each of these will implicitly have a method called "storage" which
returns their class name, for consistency.

There are some limitations to this very abstract approach, but most of
those can be overcome by defining glue functions in External's "PREP"
value. For example, if your target language is C++, and the default way
of implementing "is rw" in C++ is to expect the target function to take
a reference, then you could define your own glue function:

    module a;
    use External (language=>'C++', PREP=>q{
        int _b(int& c) { aab(&c) }
    });
    sub b(int $c is rw) is external(returns=>'int', call=>'_b');

This lets us do the quick-and-dirty conversion automatically and the
fine-grained things in the target language.

The big advantage to this mechanism is that it does not require a user
to know the internals of Perl or Parrot in order to create linkage to
external programs.

Thoughts?

-- 
Aaron Sherman X137
[EMAIL PROTECTED]

"We had some good machines, but they don't work no more."
 -"Faded Flowers" / Shriekback

Reply via email to