package Text::Wigwam::Library::Datatype;

    use strict;
    use warnings;
    our $VERSION = '0.01';

    use base q/Exporter/;

    use Text::Wigwam::Const qw/ VAR STRING ANY HASH ARRAY /;

    our %EXPORT_TAGS = (
        all => [
            qw{_proto_array         _array},
            qw{_proto_defined       _defined},
            qw{_proto_hash          _hash},
            qw{_proto_is_array      _is_array},
            qw{_proto_is_blessed    _is_blessed},
            qw{_proto_is_code_ref   _is_code_ref},
            qw{_proto_is_expr       _is_expr},
            qw{_proto_is_list       _is_list},
            qw{_proto_is_num        _is_num},
            qw{_proto_is_string     _is_string},
            qw{_proto_is_hash       _is_hash},
            qw{_proto_is_scalar     _is_scalar},
            qw{_proto_ref           _ref},
            qw{_proto_scalar        _scalar},
        ],
        array         => [ qw{_proto_array         _array}         ],
        defined       => [ qw{_proto_defined       _defined}       ],   
        hash          => [ qw{_proto_hash          _hash}          ],
        is_array      => [ qw{_proto_is_array      _is_array}      ],
        is_code_ref   => [ qw{_proto_is_code_ref   _is_code_ref}   ],
        is_expr       => [ qw{_proto_is_expr       _is_expr}       ],
        is_list       => [ qw{_proto_is_list       _is_list}       ],
        is_num        => [ qw{_proto_is_num        _is_num}        ],
        is_scalar     => [ qw{_proto_is_scalar     _is_scalar}     ],
        is_string     => [ qw{_proto_is_string     _is_string}     ],
        is_hash       => [ qw{_proto_is_hash       _is_hash}       ],
        ref           => [ qw{_proto_ref           _ref}           ],
        scalar        => [ qw{_proto_scalar        _scalar}        ],
    );
    our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
    our @EXPORT = qw( );

=head1 Name

Text::Wigwam::Library::Datatype - A Wigwam directive library.

=head1 Description

This library provides directives which are useful for detecting and casting
data types.

=head1 Usage

The directives within this library can be imported into specific branches of
the directive tree (which transcends from  C<Text::Wigwam::Directives>) via
plug-ins or modules using one of the following techniques.

 package Text::Wigwam::Directives::some::arbitrary::branch;
 # import everything
 use Text::Wigwam::Library::Datatype qw/:all/;

 package Text::Wigwam::Directives::another::arbitrary::branch;
 # import selectively
 use Text::Wigwam::Library::Datatype( qw/
  :scalar :array :hash :ref :defined :is_blessed :is_num
  :is_scalar :is_array :is_list :is_hash :is_expr :is_string :is_code_ref
 / );

=head1 Directives

=cut

sub _proto_array { [ ARRAY ] }
sub _array { $_[0]->get_arg }

=head2 #array I<arg>

Casts I<arg> into an array.

 [!!
  #define arr #array "foo"
  arr:0 /* foo */
 !!]

The C<#array> directive is typically aliased to the @ character, so the
previous example can also be written like so:

 [!!
  #define arr @ "foo"
  arr:0 /* foo */
 !!]

=cut

sub _proto_defined { [ VAR ] }
sub _defined { return $_[0]->is_defined( $_[0]->get_arg ) }

=head2 #defined I<var>

Returns true if I<var> contains an assigned value, even if it is a null
string.

 [!!
  #define array ( "" )
  #define array:8 ""
  #for { #define x 0 } { #lt x array } { #inc x } {
    #if #defined array:[x] { 'element ' x ' is defined\n' }
  }
  /*  output:
 element 0 is defined
 element 8 is defined
 */
 !!]

=cut

sub _proto_hash { [ HASH ] }
sub _hash { $_[0]->get_arg }

=head2 #hash I<arg>

The C<#hash> directive casts I<arg> into a hash. It is typically used to cast
an array into a hash which makes it possible to define complex structures
within templates.

 [!!
  #define complex #hash (
     "key1" "value"
     "key2" "value"
     "key3" "value"
     "nest" #hash (
         "key1" "value"
         "key2" "value"
     )
  )
 !!]

Perl equivalent:

 $varspace->{complex} = {
     key1 => "value",
     key2 => "value",
     key3 => "value",
     nest => {
         key1 => "value",
         key2 => "value"
     }
 }

The C<#hash> directive is typically aliased to the C<%> character, so the
previous example can also be written like so:

 [!!
  #define complex %(
     "key1" "value"
     "key2" "value"
     "key3" "value"
     "nest" %(
         "key1" "value"
         "key2" "value"
     )
  )
 !!]

=cut

sub _proto_is_array { _proto_is_list(@_) }
sub _is_array { _is_list(@_) }

=head2 #is_array I<arg>

Returns true if I<arg> is an array.

 [!! #if #is_array thing "The thing is an array!" !!]

=cut

sub _proto_is_blessed { [ ANY ] }
sub _is_blessed { return $_[0]->is_blessed( $_[0]->get_arg ) }

=head2 #is_blessed I<arg>

Returns the name of the package that I<arg> is blessed into, or false if it's
unblessed.

 [!! "It's a " #or #is_blessed thing "native type" !!]

sub _proto_is_code_ref { [ ANY ] }
sub _is_code_ref { $_[0]->is_code( $_[0]->get_arg ) }

=head2 #is_code_ref I<arg>

Returns true if I<arg> is a code reference.

 [!! #if #is_code_ref var "var is a code reference!" !!]

=cut

sub _proto_is_expr { [ ANY ] }
sub _is_expr { $_[0]->is_expr( $_[0]->get_arg ) }

=head2 #is_expr I<arg>

Returns true if I<arg> is a Wigwam expression object.

 [!! #if #is_expr thing "The thing is a Wigwam expression object!" !!]

=cut

=head2 #is_hash I<arg>

Returns true if I<arg> is a hash.

 [!! #if #is_hash thing "The thing is a hash!" !!]

=cut

sub _proto_is_list { [ ANY ] }
sub _is_list { $_[0]->is_list( $_[0]->get_arg )  }

=head2 #is_list I<arg>

Returns true if I<arg> is an array (same as C<#is_array>).

 [!! #if #is_list thing "The thing is an array!" !!]

=cut

sub _proto_is_num { [ STRING ] }
sub _is_num { $_[0]->is_num( $_[0]->get_arg ) }

=head2 #is_num I<arg>

Returns true if I<arg> is a valid numeric value.

 [!! #if #is_num "012.1E10" "Valid" /* output: Valid */ !!]

=cut

sub _proto_is_string { [ ANY ] }
sub _is_string { $_[0]->is_string( $_[0]->get_arg ) }

=head2 #is_string I<arg>

Returns true if I<arg> is a string.

 [!! #if #is_string thing "The thing is a string!" !!]

=cut

sub _proto_is_hash { [ ANY ] }
sub _is_hash { $_[0]->is_hash( $_[0]->get_arg ) }

sub _proto_is_scalar { [ ANY ] }
sub _is_scalar { $_[0]->is_scalar( $_[0]->get_arg ) }

=head2 #is_scalar I<arg>

Returns true if I<arg> is scalar reference.

 [!! #if #is_scalar thing "The thing is a scalar reference!" !!]

=cut

sub _proto_ref { [ ANY ] }
sub _ref { ref $_[0]->get_arg }

=head2 #ref I<arg>

Returns the reference type of I<arg>.

 [!! #if #eq "ARRAY" #ref thing "thing contains an array!" !!]

=cut

sub _proto_scalar { [ STRING ] }
sub _scalar { $_[0]->get_arg }

=head2 #scalar I<arg>

Casts I<arg> to a scalar.

 [!! #scalar ( "a" "b" "c" ) /* output: 3 */ !!]

...which is the size of the array which we are casting to a scalar.

Typically, the C<#scalar> directive is aliased to the $ character, in which
case preceding example could also be coded like so:

 [!! $( "a" "b" "c" ) /* output: 3 */ !!]

=cut

1;
