After banging my head against a wall for a few hours with Perl 5's XS, I have an idea for how Parrot can do it better.
Basically, the big problems with XS are: -It's ugly as hell -It makes the extender do tons of extra work -It seriously munges your code However, it has a few good features too, especially the concept of typemaps. (They look just as bad as the rest of XS, but the idea is sound.) So, how do we keep the good and rid ourselves of the bad? Here's an example of my proposed format. /* optional */ parrot_xs { xs_version => 0.1, parrot_version => 0.0.3 }; #include <math.h> /* not sure if we need this */ module { name => Math::Round, version => 1.0.3 }; extern int floor(double); extern int ciel(double); int round(double num) { int flr=floor(num); if(num < flr + 0.5) { return flr; } else { return ciel(num); } } /* Actually, these and a few other simple mappings would probably be built in, but you get the idea. */ typemap { double { type => Parrot_Float, from => CAST, to => CAST }, int { type => Parrot_Int, from => CAST, to => CAST }, char * { type => Parrot_String, from => { return Parrot_string_to_chars(interpreter, }, to => { return Parrot_string_make(interpreter, arg, strlen(arg)); } } }; As you can see, it's basically C with a few struct-looking things. It's not quite as simple as Inline::C, but it's much closer to that than Perl 5 XS. The first struct-like thing, 'parrot_xs', does version assertions and probably would also do some options. (I have no idea what those options would be, but whatever...) The second, 'module', describes the extension. It gives a name and a version. The name will probably only be needed if we mangle the opcode names, the function names, or both. I think we'll need it for something, but I'm not sure. Then come the function definitions. Any function not declared static is exposed, including the two extern ones. Finally, we have the typemap. This is the most complicated one. It consists of: FINALTYPE { type => TYPE, from => BLOCK_TO_CHANGE_FROM_TYPE_TO_FINALTYPE, to => BLOCK_TO_CHANGE_FROM_FINALTYPE_TO_TYPE } Basically, here's how it works: Parrot understands five types--INTVAL, FLOATVAL, STRING*, PMC*, and a pointer type (either void* or DPOINTER*). It knows how to convert between these types. The from block is a function that's called to transform from one of those five types to the type we actually want. The to block converts from the type we actually wanted to one of the five types. If you got a PMC and wanted a char *, the actual code would look something like this: TypeMap_Parrot_String_TO_char_PTR(interpreter, pmc->vtable->get_string(interpreter, pmc)); That function would have this definition: char * TypeMap_Parrot_String_TO_char_PTR(struct Parrot_Interp *interpreter, Parrot_String arg) { return Parrot_string_to_chars(interpreter, arg); } Note that for most extensions you won't even need a typemap. These three and a few others would likely be built-in. The biggest need for this would probably be when you're working with C structs. The link between an extension sub and Parrot bytecode is an opcode. The round() opcodes would probably be like this: op round(out INT, in NUM) { $1=(INTVAL)round((FLOATVAL)$2); goto NEXT(); } op round(out PMC, in PMC) { $1->vtable->set_integer(interpreter, $1, round($2->vtable->get_number(interpreter, $2))); } (Actually, those names might be mangled, as might the name for the C-level round() function. I'll have to figure that out.) I'm sure other people have ideas on this. Let 'em fly--the more the merrier. --Brent Dax [EMAIL PROTECTED] Parrot Configure pumpking, regex hacker, embedding coder, and boy genius #define private public --Spotted in a C++ program just before a #include