Attean

 view release on metacpan or  search on metacpan

lib/AtteanX/Functions/CompositeMaps.pm  view on Meta::CPAN


=head1 NAME

AtteanX::Functions::CompositeMaps - Functions and aggregates to work with composite maps

=head1 VERSION

This document describes AtteanX::Functions::CompositeMaps version 0.032

=head1 SYNOPSIS

  use v5.14;
  use Attean;

=head1 DESCRIPTION

This is a utility package that defines functions and aggregates to work with
composite map datatypes.

=over 4

=cut

package AtteanX::Functions::CompositeMaps::TurtleLexerWithNull {
	use Moo;
	use AtteanX::Serializer::TurtleTokens;
	use AtteanX::Parser::Turtle;
	use AtteanX::SPARQL::Constants;
	extends 'AtteanX::Parser::Turtle::Lexer';

	sub get_token {
		my $self	= shift;
		while (1) {
			$self->fill_buffer unless (length($self->buffer));

			my $start_column	= $self->column;
			my $start_line		= $self->line;

			if ($self->buffer =~ /^[ \r\n\t]+/o) {
				my $ws	= $self->read_length($+[0]);
				# we're ignoring whitespace tokens, but we could return them here instead of falling through to the 'next':
				unless ($self->ignore_whitespace) {
		 			return $self->new_token(WS, $start_line, $start_column, $ws);
				}
				next;
			}

			my $c	= $self->peek_char();
			return unless (defined($c));
			if ($c eq ':') {
				$self->read_length(1);
				return AtteanX::Parser::Turtle::Token->fast_constructor(PREFIXNAME, -1, -1, -1, -1, [':']);
			}
			if ($self->buffer =~ /^null\b/) {
				$self->read_length($+[0]);
				return 1;
			} elsif ($self->buffer =~ /^(true|false)\b/) {
				my $bool	= $self->read_length($+[0]);
				return $self->new_token(BOOLEAN, $start_line, $start_column, $bool);
			}
			return $self->SUPER::get_token();
		}
	}
}

package AtteanX::Functions::CompositeMaps 0.032 {

	use Attean;
	use Attean::RDF;
	use Encode qw(decode_utf8);
	use Scalar::Util qw(blessed);
	use Digest::SHA qw(sha1_hex);
	use AtteanX::Serializer::TurtleTokens;
	use AtteanX::Parser::Turtle;
	use AtteanX::SPARQL::Constants;
	use AtteanX::Functions::CompositeLists;
	
	our $CDT_BASE		= 'http://w3id.org/awslabs/neptune/SPARQL-CDTs/';
	our $MAP_TYPE_IRI	= "${CDT_BASE}Map";

	# Assume the opening token of the cdt has already been consumed.
	# Return either a HASH or ARRAY reference, depending on the closing token.
	# Does not validate the lexical form with respect to balanced cdt tokens.
	sub _recursive_lexer_parse_cdt {
		my $p		= shift;
		my $lexer	= shift;
		my @nodes;
		my $s		= AtteanX::Serializer::TurtleTokens->new( suppress_whitespace => 1 );
		while (my $t = $p->_next_nonws($lexer)) {
			if ($t and not blessed($t)) {
				# this is the special value returned from our lexer subclass that indicates a null values
				push(@nodes, undef);
			} else {
				next if ($t->type == COMMA);
				next if ($t->type == PREFIXNAME and $t->value eq ':'); # COLON
				
				if ($t->type == LBRACE) {
					my $hash		= _recursive_lexer_parse_cdt($p, $lexer);
					push(@nodes, AtteanX::Functions::CompositeMaps::map_to_lex(%$hash));
				} elsif ($t->type == RBRACE) {
					my %hash;
					die "odd number of map elements" unless (scalar(@nodes) % 2 == 0);
					while (my ($k, $v) = splice(@nodes, 0, 2)) {
						my @tokens;
						push(@tokens, $k->sparql_tokens->elements);
						my $iter	= Attean::ListIterator->new( values => \@tokens, item_type => 'AtteanX::Parser::Turtle::Token' );
						my $bytes	= $s->serialize_iter_to_bytes($iter);
						my $key_string	= decode_utf8($bytes);
						
						$hash{ $key_string }	= $v;
					}
					return \%hash;
				} elsif ($t->type == LBRACKET) {
					my $subnodes	= _recursive_lexer_parse_cdt($p, $lexer);
					push(@nodes, AtteanX::Functions::CompositeLists::list_to_lex(@$subnodes));
				} elsif ($t->type == RBRACKET) {
					return \@nodes;
				} else {
					my $t	= $p->_object($lexer, $t);
					push(@nodes, $t);
				}



( run in 2.603 seconds using v1.01-cache-2.11-cpan-97f6503c9c8 )