=head1 NAME

Inline::SLang::Types - Support for S-Lang types

=head1 SYNOPSIS

  use Inline SLang;
  use Math::Complex;

  # $val is a Math::Complex object after this call
  my $val = makecplx();
  print "Perl has been sent $val\n";
  # note: the multiplication is done using Math::Complex
  printcplx( $val * cplx(0,1) );

  my $type = typecplx($val);
  print "And the S-Lang datatype is $type\n";
  print "        Perl               " .  ref($type) . "\n";

  __END__
  __SLang__

  define makecplx() { return 3 + 4i; }
  define printcplx(cval) {
    () = printf( "S-Lang has been sent %s\n", string(cval) );
  }
  define typecplx(cval) { return typeof(cval); }

=head1 DESCRIPTION

 ***
 *** This is currently a pre alpha release.
 *** Use at your own risk
 ***

The aim is to allow a user to program "naturally" in Perl
and S-Lang, and so native data types are used wherever
possible. However, objects are used when necessary
(for some un-defined definition of necessary) to preserve type
information. As an example, consider swapping a complex
number between S-Lang and Perl. In S-Lang it would be represented
as a C<Complex_Type> and in Perl we choose to use a
C<Math::Complex> object. Something simple - such as
an array reference containing two elements - could have
been used, but then we would not be able to convert it
back into a C<Complex_Type> variable in S-Lang (well, not
without telling the computer this is what we wanted).

An alternative is to use L<the Perl Data Language (ie PDL)|PDL>,
since it provides variables ("piddles") which retain
type information and are optimised for numeric work.
Support for PDL is planned (once the initial kinks of the
perl interface have been worked out)
but currently not implemented (as of v0.05). Note that this
will not remove the need for a number of object
types, such as C<Inline::SLang::struct>.

=head2 Supported Perl Data Types

 ***
 *** NOTE: actually, for unsupported types we currently die
 ***

The following data types may be passed from Perl into S-Lang. Any
unrecognized type is replaced with C<undef> during translation.

I am leaning towards returing some sort of opaque reference
for unrecognized types - eg C<Inline::SLang::unknown> - 
so that the perl code won't be able
to access them but will be able to pass them along to other
S-Lang routines which can use them. This is necessary to
allow support of modules and/or packages which may define
new types. We may be able to make the class name more
meaningful (i.e. replace C<unknown> by the S-Lang type
of the variable). Or we may not.

=over 4

=item *

undef

Converted to C<NULL>.

See discussion above (e.g. C<Inline::SLang::unknown>).

=item *

Integer

Converted to S-Lang C<Integer_Type>.

=item *

Floating Point

Converted to S-Lang C<Double_Type>.

=item *

C<Math::Complex>

Converted to S-Lang C<Complex_Type>.

=item *

String

Converted to S-Lang C<String_Type>.

=item *

Inline::SLang::DataType_Type

Converted to S-Lang C<DataType_Type>.

=item *

Inline::SLang::Struct_Type

Converted to S-Lang C<Struct_Type>.

LEAKS MEMORY.

=item *

Inline::SLang::Ref_Type

Converted to S-Lang C<Ref_Type>.

=item *

Array Reference

*** NOT SUPPORTED ***

I am leaning towards returning an array of type
C<Any_Type>, since there's no guarantee that the perl
array will be of one type, or form a regular nD array.

=item *

Hash Reference

*** NOT SUPPORTED ***

This should be converted to a S-Lang C<Assoc_Type> object.
Since we don't know the types of all the elements in
the Perl hash array, it's simplest to always create 
the values as C<Any_Type> variables. That's if I 
actually knew how to do that...

=item *

all others

*** NOT SUPPORTED ***

=back

=head2 Supported S-Lang Data Types

The following S-Lang types may be returned from a S-Lang function to
Perl. Unrecognized types currently cause the code to die
(or perhaps to return undef; I really should check).

=over 4

=item *

NULL

Converted to a perl undef.

=item *

[Char|UChar|Short|UShort|Int|UInt|Long|ULong]_Type

Converted to a perl integer. The unsigned types are
converted as unsigned values, whatever difference that
makes.

=item *

[Float|Double]_Type

Converted to a perl floating-point number.

=item *

Complex_Type

Converted to a C<Math::Complex> object.

=item *

String_Type

Converted to a perl string.

=item *

DataType_Type

An object of class C<Inline::SLang::DataType_Type> is
returned.
See L<below|/"DATATYPE CLASSES"> for further details.

=item *

Ref_Type

An object of class C<Inline::SLang::Ref_Type> is
returned.
See L<below|/"DATATYPE CLASSES"> for further details.

=item *

Array_Type

Converted to a perl array reference. Currently
only 1 and 2 dimensional arrays of numeric (including
complex numbers) and strings are handled.

=item *

Assoc_Type

*** Partially supported ***

A reference to a hash array is returned. However, this
only works if the values stored in the array are of
a type which we can convert into a 1D array. So,
'C<variable a = Assoc_Type [Int_Type];>' will be converted,
but 'C<variable b = Assoc_Type [];>' will not, since we
do not currently support C<Any_Type> objects.

=item *

Struct_Type

An object of class C<Inline::SLang::Struct_Type> is
returned.
See L<below|/"DATATYPE CLASSES"> for further details.

=item *

all others

*** NOT SUPPORTED ***

Will likely use the C<Inline::SLang::unknown> class (or
at least someting that resembles this idea).

=back

=head1 DATATYPE CLASSES

 ***
 *** Comments would be welcome on the following approach
 *** It could be less verbose (particularly the
 *** Inline::SLang::*** class names), but I think the
 *** current approach is somewhat logical/easy to follow
 ***

Objects are used to represent those S-Lang data types for 
which there is no corresponding Perl data type:
for complex numbers we use the L<Math::Complex|Math::Complex> 
module which is distributed with Perl;
for numeric types we may use piddles (see the documentation 
for the L<Perl Data Language|PDL>);
and for other types we use a class specific to
Inline::SLang.

=head2 Complex numbers

Complex numbers are represented as C<Complex_Type> in 
S-Lang and as a
L<Math::Complex|Math::Complex> object in Perl. See the
L<Math::Complex|Math::Complex> documentation for
information on how to use this class.

=head2 Numeric types as piddles

 ***
 *** Support for PDL is not yet available (v0.05)
 ***

The L<Perl Data Language (PDL)|PDL> is a set of perl
modules designed to provide fast, efficient, numeric
capabilities in Perl (if you routinely deal with arrays
of numbers in Perl you should have a look at
PDL; see http://pdl.perl.org/). 

Currently S-Lang arrays are converted to Perl array references
(as discussed below). This is fine for strings (and is the
obvious representation), and does allow easy access to the
data. However, for numeric arrays it's not the most
efficient and presents issues when converting Perl to S-Lang
data [ie one would have to loop through the entire array to
work out what S-Lang datatype and dimensionality/sizes to use].
Perhaps we should use a reference to a scalar as done
in L<Astro::FITS::CFITSIO|Astro::FITS::CFITSIO>, but this 
approach has it's own issues (how do we find out the 
size of the array?).

It is likely that a routine will be used to define
whether S-Lang numeric arrays should be turned into
piddles or references to perl arrays (following the
approach of the L<Astro::FITS::CFITSIO|Astro::FITS::CFITSIO>
module). However, unlike the CFITSIO module, I am likely
to convert to either a perl array reference or
a piddle - ie no reference to a character array
representing the data (ie force users to use piddles if
they want efficiency).

=head2 Other types

A number of S-Lang types do not map to an obvious Perl
type. For these types, Inline::SLang creates
an object of class C<< Inline::SLang::<type> >>,
where C<< <type> >> is the name of the S-lang datatype
(i.e. the output of S-Lang's C<typeof> function).

Each class provides a number of methods, as listed below.
These methods are not exported into the calling packages
namespace, so they can I<only> be accessed using the
"object-oriented" form, i.e.

  $obj->foo()

Note that the C<new()> method is not defined for
some classes, which means you can only create them
by calling a S-Lang function.

=head3 Common methods

All classes provide the following methods:

=over 4

=item typeof()

Returns a string containing the name of the S-Lang datatype
of the object (which corresponds to the name of the
Perl class without the leading C<Inline::SLang::>).

=item stringify()

The "print" method for the objects has been 
over-loaded to use the C<stringify()> method:
for most types it will return the datatype name (namely
the output of the C<typeof()> method), whereas for certain
classes - such as C<Inline::SLang::Struct_Type> - it will
print out a formated representation of the data. 

The class descriptions below describe the output format
if it does not match that of the C<typeof()> method.

=item is_struct_type()

Returns a 1 if the object represents a S-Lang structure,
and 0 otherwise.
This is currently rather useless since the only class 
for which a 1 is returned is C<Inline::SLang::Struct_Type>.
It has been introduced in the hope that we will be able
to create objects for "named" structures (ie
those created via S-Lang's C<typedef> command).

=back

=head2 DataType_Type

S-Lang C<Datatype_Type> values are represented using
C<Inline::SLang::DataType_Type> objects.

The class-specific methods are:

=over 4

=item new()

  $dtype = Inline::SLang::DataType_Type->new($type);

The C<new()> method accepts a string (C<$type>) 
containing the name of the S-Lang datatype (e.g.
"UChar_Type").

=item stringify()

The name of the datatype represented by the
object is returned.

For instance

  $type = Inline::SLang::DataType_Type->new("Any_Type");
  print("And the type is '$type'\n");

outputs

  And the type is 'Any_Type'.

Note that the C<typeof()> method returns the
string "DataType_Type" and I<not> the value of the
variable.

=back

=head2 Struct_Type

 ***
 *** I want to represent structures like
 ***   typedef struct {...} FooBar_Struct;
 *** as Inline::SLang::FooBar_Struct objects 
 *** but I need to think about this/work on it
 *** first ...
 ***

S-Lang structures - variables with a type of C<Struct_Type> -
are represented using
C<Inline::SLang::Struct_Type> objects.

The methods are similar to the S-Lang versions, although
C<struct_> has been removed from the names and the get and
set functions allow multiple fields to be specified in a single
call. Not all S-Lang functions are available, although
the functionality of the missing functions should be possible
with the current interface.

Missing are

  set_struct_fields()
  _push_struct_field_values()

Need to add

  something like copy() or dup() with "field-slicing" a la
    dup_struct() in CIAO's varmm module.

The class-specific methods are:

=over 4

=item is_struct_type()

This returns 1.

=item new()

  @fields = ( "foo", "bar", "baz" );
  $s1 = Inline::SLang::Struct_Type->new(@fields);
  $s2 = Inline::SLang::Struct_Type->new(\@fields);

Create a S-Lang structure from Perl. The C<new()> method
accepts a list of field names using I<either> an
array reference or as an actual list. The order of
the array determines the order of the fields in the
structure.

It is I<not> possible to set the values of the fields
with this method (at least not for now; perhaps
we should allow a hash reference to be supplied
but then how do we define the order of the
fields?).

=item get_field_names()

 @names = $s1->get_field_names();

Returns, as an array, the names of the fields contained
in the structure. Note that, unlike S-Lang's
C<get_struct_field_names()>, it does not return an
array reference

=item get_field()

 $val  = $s1->get_field( "bar" );
 @vals = $s1->get_field( "foo", "baz" );

Returns the value of the specified field(s).
If given more than one field name then the values
are returned as an array.

The routine dies if given a field name that
does not exist in the structure.

=item set_field()

 $s1->set_field( "bar", 1 );
 $s1->set_field( foo => 23, baz => "a string" );

Sets the supplied to the supplied values. The argument list
is interpreted as pairs of "field name", "new value";
as shown above the C<< => >> separator can be used to
improve the readability of your code.

The routine dies if given a field name that
does not exist in the structure.

=item stringify()

The structure type and contents are output. The output
is currently very crude, and only really works if the
fields contain scalars. 

  @f = ( "one", "two", "three" );
  $s = Inline::SLang::Struct_Type->new(@f);
  $s->set_field("one",1,"two",2,"three",3);
  print "$s\n"; 

outputs

  Structure Type: Struct_Type
          one     = 1
          two     = 2
          three   = 3

=back

=head2 Ref_Type

S-Lang C<Ref_Type> values are represented using
C<Inline::SLang::Ref_Type> objects. Note that these
objects can I<only> be created from S-Lang
(i.e. there is no C<new()> method).
In fact, there is little that you can do with these
objects in Perl; if you want to access/change the
value referred to then you need to pass the object
back to S-Lang.

There are no class-specific methods.

=head1 SEE ALSO

L<Inline::SLang>, L<Math::Complex>, L<PDL>

=head1 AUTHOR, COPYRIGHT, LICENSE, and WARRANTY

See the L<Inline::SLang|Inline::SLang> documentation.

