use strict;
#use warnings;
package RDF::Notation3::Template::TReader;
require 5.005_62;
use Carp;
############################################################
sub get {
my ($self) = @_;
unless ($self->{tokens}->[0]) {
$self->_more_tokens;
}
return shift @{$self->{tokens}};
}
sub try {
my ($self) = @_;
unless ($self->{tokens}->[0]) {
$self->_more_tokens;
}
return $self->{tokens}->[0];
}
sub _more_tokens {
my ($self) = @_;
$self->{currentline} = $self->_new_line;
my $line = \$self->{currentline};
unless ($$line) {
push @{$self->{tokens}}, ' EOF ';
return;
}
while (1) {
last unless $$line;
my $token;
if ( $$line =~ /^\"/ ) {
my $tok = $self->_get_string;
push @{$self->{tokens}}, $tok;
}
elsif ( $$line =~ /^\s+/ ) {
$$line = $';
}
# " is sticked to the previous character, such as ("
elsif ( $$line =~ /^([^\s\"]+)\"/ ) {
$$line = '"' . $';
push @{$self->{tokens}}, $1;
}
elsif ( $$line =~ /^(\S+)/ ) {
$$line = $';
push @{$self->{tokens}}, $1;
}
}
push @{$self->{tokens}}, ' EOL ';
}
# returns a quoted string to be eval'ed
sub _get_string {
my $self = shift;
my $lineref = \$self->{currentline};
# Handle escaped newlines
my $have_escaped_newlines = ($$lineref =~ /\\\n$/);
# Check if it's a python string
if ( $$lineref =~ /^\"{3}/ ) {
return $self->_get_triple_quoted_string;
}
my @parts = split /\"/, $$lineref;
# First part should be empty
shift @parts;
my $return = "";
my $part;
while ( $part = shift @parts ) {
$return .= $part;
last unless $return =~ /\\$/;
$return .= '"';
}
# if chewed up everything and not ending in a quote
if ( @parts == 0 && $$lineref !~ /[^\\]\"$/) {
# Escaped newlines should be ignored.
if ( $have_escaped_newlines ) {
# if there are more lines
my $line = $self->_new_line(1);
if ( $line ) {
# tack them on and try again.
$$lineref .= $line;
return $self->_get_string( $lineref );
}
}
$self->_do_error(111, $$lineref);
}
$$lineref = join '"', @parts;
return "\"$return\"";
}
sub _get_triple_quoted_string {
my $self = shift;
my $lineref = \$self->{currentline};
if ( $$lineref =~ /^\"{6}/ ) {
$$lineref = $';
return "\"\"";
}
elsif ( $$lineref =~ /^\"{3}(.*?[^\\])\"{3}/ ) {
$$lineref = $';
my $tok = $1;
# quote unquoted double quotes
while ($tok =~ s/(^|[^\\])\"/$1\\\"/ ){}
return "\"$tok\"";
}
my $return = $$lineref;
my $line = "";
while ( $line = $self->_new_line(1) ) {
if ( $line =~ /^((.*?[^\\])?\"{3})/ ) {
$return .= $1;
$$lineref = $';
# remove the surrounding quotes
$return =~ s/^\"{3}//;
$return =~ s/\"{3}$//;
# Handle escaped newlines
$return =~ s/\\\n//g;
# quote unquoted double quotes
while ($return =~ s/(^|[^\\])\"/$1\\\"/ ){}
return "\"$return\"";
}
else {
$return .= $line;
}
}
# Ran out of lines!
$self->_do_error(113, $return);
}
sub _do_error {
my ($self, $n, $tk) = @_;
my %msg = (
111 => 'string1 ("...") is not terminated',
113 => 'string2 ("""...""")is not terminated',
114 => 'string1 ("...") can\'t include newlines',
);
my $msg = "[Error $n]";
$msg .= " line $self->{ln}, token" if $n > 100;
$msg .= " \"$tk\"\n";
$msg .= "$msg{$n}!\n";
croak $msg;
}
1;
__END__
# Below is a documentation.
=head1 NAME
RDF::Notation3::Template::TReader - RDF Notation3 file reader template
=head1 LICENSING
Copyright (c) 2001 Ginger Alliance. All rights reserved. This program is free
software; you can redistribute it and/or modify it under the same terms as
Perl itself.
=head1 AUTHOR
Petr Cimprich, petr@gingerall.cz
=head1 SEE ALSO
perl(1), RDF::Notation3.
=cut