#!/usr/bin/perl
#Copyright Massachusetts Institute of technology, 2003.
#Written by Eric Prud'hommeaux for the World Wide Web Consortium
#This file is PUBLIC DOMAIN.

# AlgaeCompileTree.pm -- Object definitions for populating an algae parse tree.
# 
# $Id: AlgaeCompileTree.pm,v 1.186 2007-10-13 01:40:54 eric Exp $

use strict;
package W3C::Rdf::AlgaeCompileTree;
use W3C::Util::Exception;
require Exporter;
@W3C::Rdf::AlgaeCompileTree::ISA = qw(Exporter);
use W3C::Rdf::Algae2 qw(); # &getTripleAttribute &setTripleAttribute);
use vars qw(@EXPORT_OK
	    $DISJUNCTION $NEGATION $OUTER
	    $DefaultPrecedence $MAX_PREC $LEFT $RIGHT
	    $BASE_FILE $BASE_HTTP);
@EXPORT_OK = qw($DISJUNCTION $NEGATION $OUTER $DefaultPrecedence $MAX_PREC $LEFT $RIGHT 
		$BASE_FILE $BASE_HTTP);

($DISJUNCTION, $NEGATION, $OUTER) = qw(8 13 23);
($LEFT, $RIGHT) = (1, 2);
$MAX_PREC = 9;
my $MAX_PREC = $MAX_PREC;
$DefaultPrecedence = {
    '||' => [9, $LEFT],
    '^' => [8, $LEFT],
    '.' => [7, $LEFT],
    '&&' => [7, $LEFT],
    '<' => [5, $LEFT],
    '<=' => [5, $LEFT],
    '>' => [5, $LEFT],
    '>=' => [5, $LEFT],
    '==' => [5, $LEFT],
    '+' => [3, $RIGHT],
    '-' => [3, $RIGHT],
    '*' => [2, $LEFT],
    '/' => [2, $LEFT],
    '!' => [1, $RIGHT],
    NEG => [1, $RIGHT],
};
my $DefaultPrecedence = $DefaultPrecedence;

$BASE_FILE = \ "BASE_FILE";
$BASE_HTTP = \ "BASE_HTTP";
my $BASE_FILE = $BASE_FILE;
my $BASE_HTTP = $BASE_HTTP;

# Each class corresponds to a production in the AlgaeParser grammar.

#                           ______________Action_____________
#                          /                                 \
#            __DelayedAction___              _____________ImmediateAction_______________
#           /     /     \      \            /     /     /      |    \     \             \
# TriplesAction AskAll FwRule Bindings  Attach Clear Collect Host Flags NamespaceDecl Slurp
#   /     \
# Ask    Assert

@W3C::Rdf::AlgaeCompileTree::ImmediateAction::ISA = qw(W3C::Rdf::AlgaeCompileTree::Action);
@W3C::Rdf::AlgaeCompileTree::DelayedAction::ISA = qw(W3C::Rdf::AlgaeCompileTree::Action);
@W3C::Rdf::AlgaeCompileTree::TriplesAction::ISA = qw(W3C::Rdf::AlgaeCompileTree::DelayedAction);
@W3C::Rdf::AlgaeCompileTree::AskAll::ISA = qw(W3C::Rdf::AlgaeCompileTree::DelayedAction);

@W3C::Rdf::AlgaeCompileTree::Ask::ISA = qw(W3C::Rdf::AlgaeCompileTree::TriplesAction);
@W3C::Rdf::AlgaeCompileTree::Assert::ISA = qw(W3C::Rdf::AlgaeCompileTree::TriplesAction);
@W3C::Rdf::AlgaeCompileTree::Attach::ISA = qw(W3C::Rdf::AlgaeCompileTree::ImmediateAction);
@W3C::Rdf::AlgaeCompileTree::Base::ISA = qw(W3C::Rdf::AlgaeCompileTree::ImmediateAction);
@W3C::Rdf::AlgaeCompileTree::Bindings::ISA = qw(W3C::Rdf::AlgaeCompileTree::DelayedAction);
@W3C::Rdf::AlgaeCompileTree::Clear::ISA = qw(W3C::Rdf::AlgaeCompileTree::ImmediateAction);
@W3C::Rdf::AlgaeCompileTree::CollectSet::ISA = qw(W3C::Rdf::AlgaeCompileTree::ImmediateAction);
@W3C::Rdf::AlgaeCompileTree::Collect::ISA = qw(W3C::Rdf::AlgaeCompileTree::CollectSet);
# @W3C::Rdf::AlgaeCompileTree::CollectStar::ISA = qw(W3C::Rdf::AlgaeCompileTree::CollectSet);
@W3C::Rdf::AlgaeCompileTree::SPARQLAsk::ISA = qw(W3C::Rdf::AlgaeCompileTree::Collect);
@W3C::Rdf::AlgaeCompileTree::Delete::ISA = qw(W3C::Rdf::AlgaeCompileTree::TriplesAction);
@W3C::Rdf::AlgaeCompileTree::Describe::ISA = qw(W3C::Rdf::AlgaeCompileTree::Collect);
@W3C::Rdf::AlgaeCompileTree::DescribeStar::ISA = qw(W3C::Rdf::AlgaeCompileTree::CollectStar);
@W3C::Rdf::AlgaeCompileTree::Host::ISA = qw(W3C::Rdf::AlgaeCompileTree::ImmediateAction);
@W3C::Rdf::AlgaeCompileTree::Flags::ISA = qw(W3C::Rdf::AlgaeCompileTree::ImmediateAction);
@W3C::Rdf::AlgaeCompileTree::FwRule::ISA = qw(W3C::Rdf::AlgaeCompileTree::DelayedAction);
@W3C::Rdf::AlgaeCompileTree::Pattern::ISA = qw(W3C::Rdf::AlgaeCompileTree::Assert);
@W3C::Rdf::AlgaeCompileTree::NamespaceDecl::ISA = qw(W3C::Rdf::AlgaeCompileTree::ImmediateAction);
@W3C::Rdf::AlgaeCompileTree::Require::ISA = qw(W3C::Rdf::AlgaeCompileTree::ImmediateAction);
@W3C::Rdf::AlgaeCompileTree::Slurp::ISA = qw(W3C::Rdf::AlgaeCompileTree::ImmediateAction);

# supported profiles:
# profileQuery
@W3C::Rdf::AlgaeCompileTree::ProfileQuery::ISA = qw(W3C::Rdf::AlgaeCompileTree::DelayedAction);

# Other Things
@W3C::Rdf::AlgaeCompileTree::Binding::ISA = qw(W3C::Rdf::AlgaeCompileTree::Thing);

#                       Thing
#                         |
#     ____________GraphPatternElement
#    /          /       \
# Decl   UnaryDecl      BinaryDecl
#        /    \          /       \
# Negation  Option  Conjunction  Disjunction
@W3C::Rdf::AlgaeCompileTree::GraphPattern::ISA = qw(W3C::Rdf::AlgaeCompileTree::Thing);
@W3C::Rdf::AlgaeCompileTree::GraphPatternElement::ISA = qw(W3C::Rdf::AlgaeCompileTree::Thing);
@W3C::Rdf::AlgaeCompileTree::Decl::ISA = qw(W3C::Rdf::AlgaeCompileTree::GraphPatternElement);
@W3C::Rdf::AlgaeCompileTree::UnaryDecl::ISA = qw(W3C::Rdf::AlgaeCompileTree::GraphPatternElement);
@W3C::Rdf::AlgaeCompileTree::BinaryDecl::ISA = qw(W3C::Rdf::AlgaeCompileTree::GraphPatternElement);
@W3C::Rdf::AlgaeCompileTree::Negation::ISA = qw(W3C::Rdf::AlgaeCompileTree::UnaryDecl);
@W3C::Rdf::AlgaeCompileTree::Option::ISA = qw(W3C::Rdf::AlgaeCompileTree::UnaryDecl);
@W3C::Rdf::AlgaeCompileTree::Conjunction::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryDecl);
@W3C::Rdf::AlgaeCompileTree::ShortcutDisjunction::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryDecl);
@W3C::Rdf::AlgaeCompileTree::UnionDisjunction::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryDecl);
@W3C::Rdf::AlgaeCompileTree::UnionDisjunctionMerge::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryDecl);
#@W3C::Rdf::AlgaeCompileTree::Disjunction::ISA = qw(W3C::Rdf::AlgaeCompileTree::ShortcutDisjunction);

#         _Thing_____
#        /           \
#     POS             StaticPOS_
#    /   \           /    \     \
#  Var  KeyName  BNode  Literal  UrlBase
#                           |    /   \
#                          NUM  URL  QName
@W3C::Rdf::AlgaeCompileTree::POS::ISA = qw(W3C::Rdf::AlgaeCompileTree::Thing);
@W3C::Rdf::AlgaeCompileTree::StaticPOS::ISA = qw(W3C::Rdf::AlgaeCompileTree::Thing);
@W3C::Rdf::AlgaeCompileTree::Var::ISA = qw(W3C::Rdf::AlgaeCompileTree::POS);
@W3C::Rdf::AlgaeCompileTree::NovelVar::ISA = qw(W3C::Rdf::AlgaeCompileTree::Var);
@W3C::Rdf::AlgaeCompileTree::NovelBNode::ISA = qw(W3C::Rdf::AlgaeCompileTree::NovelVar);
@W3C::Rdf::AlgaeCompileTree::KeyName::ISA = qw(W3C::Rdf::AlgaeCompileTree::POS);
@W3C::Rdf::AlgaeCompileTree::List::ISA = qw(W3C::Rdf::AlgaeCompileTree::StaticPOS);
@W3C::Rdf::AlgaeCompileTree::Members::ISA = qw(W3C::Rdf::AlgaeCompileTree::StaticPOS);
@W3C::Rdf::AlgaeCompileTree::XPath::ISA = qw(W3C::Rdf::AlgaeCompileTree::Var);
@W3C::Rdf::AlgaeCompileTree::BNode::ISA = qw(W3C::Rdf::AlgaeCompileTree::StaticPOS);
@W3C::Rdf::AlgaeCompileTree::Literal::ISA = qw(W3C::Rdf::AlgaeCompileTree::StaticPOS);
@W3C::Rdf::AlgaeCompileTree::UrlBase::ISA = qw(W3C::Rdf::AlgaeCompileTree::StaticPOS);
@W3C::Rdf::AlgaeCompileTree::Num::ISA = qw(W3C::Rdf::AlgaeCompileTree::Literal);
@W3C::Rdf::AlgaeCompileTree::Int::ISA = qw(W3C::Rdf::AlgaeCompileTree::Num);
@W3C::Rdf::AlgaeCompileTree::Decimal::ISA = qw(W3C::Rdf::AlgaeCompileTree::Num);
@W3C::Rdf::AlgaeCompileTree::Double::ISA = qw(W3C::Rdf::AlgaeCompileTree::Num);
#@W3C::Rdf::AlgaeCompileTree::Boolean::ISA = qw(W3C::Rdf::AlgaeCompileTree::Int);
@W3C::Rdf::AlgaeCompileTree::Boolean::ISA = qw(W3C::Rdf::AlgaeCompileTree::Num);
@W3C::Rdf::AlgaeCompileTree::Url::ISA = qw(W3C::Rdf::AlgaeCompileTree::UrlBase);
@W3C::Rdf::AlgaeCompileTree::DelayedQName::ISA = qw(W3C::Rdf::AlgaeCompileTree::UrlBase);
@W3C::Rdf::AlgaeCompileTree::QName::ISA = qw(W3C::Rdf::AlgaeCompileTree::DelayedQName);

# <CONSTRAINTS>
#         Thing
#         /   \
# Constraint  Expr
#            /  \
#       Unary  Binary
#      /  \     |
#    Neg  Not  Eq,Ne,Glob,Or,Xor,And,Lt,Le,Gt,Ge,Plus,Minus,Multiply,Exp,Divide,Assign
@W3C::Rdf::AlgaeCompileTree::Constraint::ISA = qw(W3C::Rdf::AlgaeCompileTree::Thing);
@W3C::Rdf::AlgaeCompileTree::Expr::ISA = qw(W3C::Rdf::AlgaeCompileTree::Thing);

@W3C::Rdf::AlgaeCompileTree::Unary::ISA = qw(W3C::Rdf::AlgaeCompileTree::Expr);
@W3C::Rdf::AlgaeCompileTree::Neg::ISA = qw(W3C::Rdf::AlgaeCompileTree::Unary);
@W3C::Rdf::AlgaeCompileTree::Not::ISA = qw(W3C::Rdf::AlgaeCompileTree::Unary);
@W3C::Rdf::AlgaeCompileTree::BitFlip::ISA = qw(W3C::Rdf::AlgaeCompileTree::Unary);
@W3C::Rdf::AlgaeCompileTree::Lang::ISA = qw(W3C::Rdf::AlgaeCompileTree::Unary);
@W3C::Rdf::AlgaeCompileTree::Label::ISA = qw(W3C::Rdf::AlgaeCompileTree::Unary);

@W3C::Rdf::AlgaeCompileTree::Binary::ISA = qw(W3C::Rdf::AlgaeCompileTree::Expr);
@W3C::Rdf::AlgaeCompileTree::Glob::ISA = qw(W3C::Rdf::AlgaeCompileTree::Binary);
@W3C::Rdf::AlgaeCompileTree::Or::ISA = qw(W3C::Rdf::AlgaeCompileTree::Binary);
@W3C::Rdf::AlgaeCompileTree::And::ISA = qw(W3C::Rdf::AlgaeCompileTree::Binary);

@W3C::Rdf::AlgaeCompileTree::BinaryTest::ISA = qw(W3C::Rdf::AlgaeCompileTree::Binary);
@W3C::Rdf::AlgaeCompileTree::EquivTest::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryTest);
@W3C::Rdf::AlgaeCompileTree::Eq::ISA = qw(W3C::Rdf::AlgaeCompileTree::EquivTest);
@W3C::Rdf::AlgaeCompileTree::Ne::ISA = qw(W3C::Rdf::AlgaeCompileTree::EquivTest);
@W3C::Rdf::AlgaeCompileTree::Lt::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryTest);
@W3C::Rdf::AlgaeCompileTree::Le::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryTest);
@W3C::Rdf::AlgaeCompileTree::Gt::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryTest);
@W3C::Rdf::AlgaeCompileTree::Ge::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryTest);
@W3C::Rdf::AlgaeCompileTree::Xor::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryTest);

@W3C::Rdf::AlgaeCompileTree::BinaryArith::ISA = qw(W3C::Rdf::AlgaeCompileTree::Binary);
@W3C::Rdf::AlgaeCompileTree::Plus::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryArith);
@W3C::Rdf::AlgaeCompileTree::Minus::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryArith);
@W3C::Rdf::AlgaeCompileTree::Multiply::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryArith);
@W3C::Rdf::AlgaeCompileTree::Exp::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryArith);
@W3C::Rdf::AlgaeCompileTree::Divide::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryArith);
@W3C::Rdf::AlgaeCompileTree::Modulo::ISA = qw(W3C::Rdf::AlgaeCompileTree::BinaryArith);

@W3C::Rdf::AlgaeCompileTree::Assign::ISA = qw(W3C::Rdf::AlgaeCompileTree::Binary);

@W3C::Rdf::AlgaeCompileTree::FuncCall::ISA = qw(W3C::Rdf::AlgaeCompileTree::Expr);
@W3C::Rdf::AlgaeCompileTree::Operator::ISA = qw(W3C::Rdf::AlgaeCompileTree::FuncCall);
# </CONSTRAINTS>

sub format {
    my ($in, $add) = @_;
    my @lines = split("\n", $in);
    return join ("\n", $lines[0], map {"$add$_"} @lines[1..@lines-1]);
}
sub main::_defaultPrec {
    my ($ob, %flags) = @_;
    if (!exists $flags{-parentPrec}) {
	$flags{-parentPrec} = $MAX_PREC;
    }
    if (!exists $flags{-precTable}) {
	$flags{-precTable} = $DefaultPrecedence;
	$flags{-parentPrec} = $MAX_PREC+1;
    }
    return ($ob, %flags);
}

package W3C::Rdf::FailureOnTypeException;
@W3C::Rdf::FailureOnTypeException::ISA = qw(W3C::Util::SafeEvaluationException);
sub new {
    my ($proto, @parms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@parms);
    $self->missingParm('-expect') if (!exists $self->{-expect});
    $self->missingParm('-got') if (!exists $self->{-got});
    $self->fillInStackTrace;
    return $self;
}

sub getSpecificMessage {return 'Safe failure: expected: '.$_[0]->getExpect.' got: '.$_[0]->getGot();}
sub getExpect {return $_[0]->{-expect}}
sub getGot {return $_[0]->{-got}}

package W3C::Rdf::ExtensionsNotSupportedException;
@W3C::Rdf::ExtensionsNotSupportedException::ISA = qw(W3C::Util::UnsafeEvaluationException);
sub new {
    my ($proto, @parms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@parms);
    $self->missingParm('-uris') if (!exists $self->{-uris});
    $self->fillInStackTrace;
    return $self;
}
sub getSpecificMessage {
    my ($self) = @_;
    my $uris = $self->getUris;
    my $urisStr = join (', ', map {"<$_>"} @$uris);
    return "Unsupported profiles: $urisStr";
}
sub getUris {return $_[0]->{-uris}}

package W3C::Rdf::UnmentionedVariableException;
@W3C::Rdf::UnmentionedVariableException::ISA = qw(W3C::Util::UnsafeEvaluationException);
sub new {
    my ($proto, @parms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@parms);
    $self->missingParm('-var') if (!exists $self->{-var});
    $self->fillInStackTrace;
    return $self;
}
sub getSpecificMessage {
    my ($self) = @_;
    my $var = $self->getVar;
    return "unknown variable $var";
}
sub getVar {return $_[0]->{-var}}

package W3C::Rdf::UnknownFunctionException;
@W3C::Rdf::UnknownFunctionException::ISA = qw(W3C::Util::UnsafeEvaluationException);
sub new {
    my ($proto, @parms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@parms);
    $self->missingParm('-function') if (!exists $self->{-function});
    $self->fillInStackTrace;
    return $self;
}
sub getSpecificMessage {
    my ($self) = @_;
    my $function = $self->getFunction;
    return "unknown function $function";
}
sub getFunction {return $_[0]->{-function}}

package W3C::Rdf::UnknownFormatException;
@W3C::Rdf::UnknownFormatException::ISA = qw(W3C::Util::UnsafeEvaluationException);
sub new {
    my ($proto, @parms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@parms);
    $self->missingParm('-format') if (!exists $self->{-format});
    $self->fillInStackTrace;
    return $self;
}
sub getSpecificMessage {
    my ($self) = @_;
    my $format = $self->getFormat;
    return "unknown format $format";
}
sub getFormat {return $_[0]->{-format}}

# #######################
# Algae Request Structure
# 
package W3C::Rdf::AlgaeCompileTree::Action;
use W3C::Util::Exception;
sub new {
    my ($proto, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    $actionParms[0] || &throw();
    my $self = {ALGAE2 => $actionParms[0]};
    bless ($self, $class);
    return $self;
}
sub toString {&throw(new W3C::Util::MethodNotImplementedException(-object => $_[0], -function => 'W3C::Rdf::AlgaeCompileTree::Action::toString'))}

package W3C::Rdf::AlgaeCompileTree::ImmediateAction;
use W3C::Util::Exception;
sub immediateEvaluate {&throw(new W3C::Util::NotImplementedException(-object => $_[0]))}
sub delayedEvaluate {}

package W3C::Rdf::AlgaeCompileTree::DelayedAction;
use W3C::Util::Exception;
sub immediateEvaluate {}
sub delayedEvaluate {&throw(new W3C::Util::NotImplementedException(-object => $_[0]))}

package W3C::Rdf::AlgaeCompileTree::Attach;
use W3C::Util::Exception;
sub new {
    my ($proto, $type, $name, $parms, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{TYPE} = $type;
    $self->{PARMS} = $parms;
    $self->{NAME} = $name;
    my $typeStr = $type->getUrl;
    # some default invocation parameters:
    if ($typeStr eq 'http://www.w3.org/1999/02/26-modules/algae#dynamic') {
	my $class = delete $parms->{-class};
	if (!$class) {
	    &throw(new W3C::Util::Exception(-message => "no class name specified for dynamic database"));
	}
	$class = $class->getString;
	my $db;
	#print "require $class; \$db = new $class(\$parms);\n";
	eval "require $class; \$db = new $class(\$parms);";
	if ($@) {if (my $ex = &catch('W3C::Util::Exception')) {
	    &throw($ex);
	    #$self->{-errorHandler}->warning($ex);
	} else {
	    &throw(new W3C::Util::Exception(-message => "got exception \"$@\" while executing \"require $class; \$db = new $class(\$parms);\"."));
	    #$self->{-errorHandler}->error(new W3C::Util::PerlException);
	}}
	$self->{DB} = $db;
    } elsif ($typeStr eq 'http://www.w3.org/1999/02/26-modules/algae#federated') {
	require W3C::Rdf::SparqlFed;
	foreach my $binding (@{$self->{BINDINGS}}) {
	    my ($attr, $value) = ($binding->{NAME}, $binding->{VALUE});
	    $parms->{'-'.$attr} = $value;
	}
	$self->{DB} = new W3C::Rdf::SparqlFed($parms, $self->{ALGAE2});
    } elsif ($typeStr eq 'http://www.w3.org/2003/01/21-RDF-RDB-access/ns#SqlDB') {
	require W3C::Rdf::SqlDB;
	foreach my $binding (@{$self->{BINDINGS}}) {
	    my ($attr, $value) = ($binding->{NAME}, $binding->{VALUE});
	    $parms->{'-'.$attr} = $value;
	}
	$self->{DB} = new W3C::Rdf::SqlDB($parms);
    } elsif ($typeStr eq 'http://www.w3.org/1999/02/26-modules/algae#sql') {
	require W3C::Rdf::SqlDB;
	foreach my $binding (@{$self->{BINDINGS}}) {
	    my ($attr, $value) = ($binding->{NAME}, $binding->{VALUE});
	    $parms->{'-'.$attr} = $value;
	}
	$self->{DB} = new W3C::Rdf::SqlDB($parms);
    } elsif ($typeStr eq 'http://www.w3.org/2004/10/16-RDF-FileSystem/ns#FSDB') {
	require W3C::Rdf::FileSystemDB;
	foreach my $binding (@{$self->{BINDINGS}}) {
	    my ($attr, $value) = ($binding->{NAME}, $binding->{VALUE});
	    $parms->{'-'.$attr} = $value;
	}
	$self->{DB} = new W3C::Rdf::FileSystemDB($parms);
    } elsif ($typeStr eq 'http://www.w3.org/1999/02/26-modules/algae#ephemeral') {
	require W3C::Rdf::RdfDB;
	foreach my $binding (@{$self->{BINDINGS}}) {
	    my ($attr, $value) = ($binding->{NAME}, $binding->{VALUE});
	    $parms->{'-'.$attr} = $value;
	}
	$self->{DB} = new W3C::Rdf::RdfDB($parms);
    } else {
	&throw(new W3C::Util::Exception(-message => "unknown database \"$typeStr\""));
    }

    $self->{ALGAE2}->addSource($name->getUrl, $self->{DB});
    return $self;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return "attach '(\"$self->{TYPE}\" (".join (' ', map {$_->toString(%flags)} @{$self->{BINDINGS}}).'))';
}
package W3C::Rdf::AlgaeCompileTree::Binding;
sub new {
    my ($proto, $name, $value, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{NAME} = $name;
    $self->{VALUE} = $value;
    return $self;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return $self->{NAME}.'='.($self->{VALUE}); # ->toString
}
package W3C::Rdf::AlgaeCompileTree::NamespaceDecl;
sub new {
    my ($proto, $prefix, $namespace, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{PREFIX} = $prefix;
    $self->{NAMESPACE} = $namespace;
    return $self;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    if ($flags{-lang} eq 'SPARQL') {
	return "PREFIX $self->{PREFIX}: <$self->{NAMESPACE}>";
    } else {
	my $prefixStr = $self->{PREFIX} ? "$self->{PREFIX}=" : '';
	return "namespace $prefixStr<$self->{NAMESPACE}>";
    }
}
package W3C::Rdf::AlgaeCompileTree::Flags;
use W3C::Rdf::Atoms qw($ATTRIB_GroundFact);
sub new {
    my ($proto, $bindings, $setOp, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{BINDINGS} = $bindings;
    $self->{SET_OP} = $setOp;
    return $self;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
    my $defaultParms = $self->{ALGAE2}->getDefaultParms;
    if ($self->{SET_OP} eq '') {
	foreach my $key (keys %$defaultParms) {
	    delete $defaultParms->{$key};
	}
    }
    foreach my $binding (@{$self->{BINDINGS}}) {
	my ($attr, $value) = ($binding->{NAME}, $binding->{VALUE});
	if ($attr->isa('W3C::Rdf::AlgaeCompileTree::KeyName')) {
	    my $keyName = $attr->getName;
	    if ($keyName eq 'ATTRIB') {
		my $auth = undef; # !!!
		$attr = '-sourceAttribution';
		$value = $self->{ALGAE2}{-atomDictionary}->getGroundFactAttribution(
							    $value->interned, 
							    undef, $auth, undef);
	    } else {
		&throw(new W3C::Util::Exception(-message =>"unknown key word \"$keyName}\""));
	    }
	}
	if ($self->{SET_OP} eq '-') {
	    delete $defaultParms->{$attr};
	} else {
	    $defaultParms->{$attr} = $value;
	}
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return "flags $self->{SET_OP} (".join(' ', map {$_->toString(%flags)} @{$self->{BINDINGS}}).")";
}

package W3C::Rdf::AlgaeCompileTree::FwRule;
use W3C::Util::ArrayUtils qw(&DecorateArray);
use W3C::Rdf::Atoms qw($ATTRIB_GroundFact);
my $FwRuleAtoms = {};
sub new {
    my ($proto, $body, $head, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $FwRuleAtoms->{$class}{$body}{$head};
    if (!$self) {
	$self = $class->SUPER::new(@actionParms);
	$self->{BODY} = $body;
	$self->{HEAD} = $head;
	$FwRuleAtoms->{$class}{$body}{$head} = $self;
    }
    my $atoms = $self->{ALGAE2}{-atomDictionary};
    $self->{RULE_RESULT_SET} = new W3C::Rdf::ChildResultSet($self->{ALGAE2}->getResultSet, -atomDictionary => $atoms);
    $self->{ATTRIBUTION} = new W3C::Rdf::AttributionList();
    $self->{ATTRIBUTION}->ensureDirectAttribution($self->{ALGAE2}->getSourceAttribution);
    return $self;
}
sub delayedEvaluate {
    my ($self, $resultSet) = @_;
    $self->{BODY}->getDB->addForwardChainingRule($self, $self->{BODY}->getDB, $self->{RULE_RESULT_SET}, $self->{ATTRIBUTION});
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my ($open, $close) = ('', '');
    if ($flags{-htmlClassMap} && (my $class = $flags{-htmlClassMap}{ref $self})) {
	($open, $close) = ("<div class=\"$class\">", "</div>");
    }
    my @a;
    if (!$flags{-brief}) {
	@a = $self->{ATTRIBUTION}->toString(%flags);
    }
    if (wantarray) {
	return $flags{-outputMode} eq 'n3' ? 
	    (' a :FwRule ; ', 
	     &DecorateArray(' :repr {{ ', '         ', '', ' }', $self->{BODY}->toString(%flags)), 
	     '         => ', 
	     &DecorateArray('        { ', '         ', '', ' }} ;', $self->{HEAD}->toString(%flags)), 
	     &DecorateArray(' :accordingTo ', '              ', '', '', @a)) : 
	     &DecorateArray("${open}fwrule ", '       ', '', $close, 
			    ($self->{BODY}->toString(%flags), 
			     $self->{HEAD}->toString(%flags), 
			     &DecorateArray('   -->', '             ', '', '', @a)));
    } else {
	my $aStr = @a ? ' '.join (' ', @a) : '';
	return 'fwrule '.$self->{BODY}->toString(%flags).' '.
	    $self->{HEAD}->toString(%flags).$aStr;
    }
}
sub getBody {$_[0]->{BODY}}
sub getHead {$_[0]->{HEAD}}

package W3C::Rdf::AlgaeCompileTree::Pattern;
sub getActionName {'pattern'}
sub toAsk {
    my ($self, $morePatterns) = @_;
    my $decls = $self->{DECLS};
    foreach my $pattern (@$morePatterns) {
	$decls = new W3C::Rdf::AlgaeCompileTree::Conjunction($decls, $pattern->{DECLS}, $decls->{PARSER});
    }
    return new W3C::Rdf::AlgaeCompileTree::Ask($decls, $self->getDB(), $self->getDB(), $decls->{ALGAE2});
}

package W3C::Rdf::AlgaeCompileTree::Base;
use W3C::Util::Exception;
sub new {
    my ($proto, $base, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{BASE} = $base;
    return $self;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
    if ($self->{BASE} == $BASE_FILE) {
	require File::Spec;
	my $curdir = `pwd`;
	chomp $curdir;
	if ($curdir eq '/') {
	    $curdir = '';
	} else {
	    $curdir = "$curdir/";
	}
	my $source = $self->{ALGAE2}{-atomDictionary}->getUri("file://localhost/$curdir");
	my $attrib = $self->{ALGAE2}{-atomDictionary}->getGroundFactAttribution($source, undef, undef, undef);
	$self->{ALGAE2}->setSourceAttribution($attrib);
    } elsif ($self->{BASE} == $BASE_HTTP) {
	my $curUri = $self->{ALGAE2}->getSourceAttribution()->getSource()->getUri();
	if ($curUri =~ m//) {
	    # hmm, we already have the right one.
	} else {
	    &throw(new W3C::Util::Exception(-message => "no idea what the current HTTP location is from \"$curUri\""));
	}
    } elsif (UNIVERSAL::isa($self->{BASE}, 'W3C::Rdf::AlgaeCompileTree::UrlBase')) {
	my $source = $self->{ALGAE2}{-atomDictionary}->getUri($self->{BASE}->getUrl());
	my $attrib = $self->{ALGAE2}{-atomDictionary}->getGroundFactAttribution($source, undef, undef, undef);
	$self->{ALGAE2}->setSourceAttribution($attrib);
    } else {
	&throw(new W3C::Util::Exception(-message => "base \"$self->{BASE}\" not recognized"));
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $baseStr = $self->{BASE} == $BASE_FILE ? 'file' : 
	$self->{BASE} == $BASE_HTTP ? 'http' : 
	$self->{BASE}->toString(%flags);
    return "base $baseStr";
}

package W3C::Rdf::AlgaeCompileTree::Bindings;
use W3C::Util::ArrayUtils qw(&DecorateArray);
use W3C::Rdf::Atoms qw($Value_NULL);
my $BindingsAtoms = {};
sub new {
    my ($proto, $vars, $bindings, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{VARS} = $vars;
    $self->{BINDINGS} = $bindings;
    return $self;
}
sub delayedEvaluate {
    my ($self, $resultSet) = @_;
    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	foreach my $binding (@{$self->{BINDINGS}}) {
	    my $newRow = $row->duplicate;
	    for (my $i = 0; $i < @$binding; $i++) {
		$self->{VARS}[$i]->absorb($binding->[$i] ? $binding->[$i]->val : undef, $newRow, undef);
	    }
	}
	$row->eliminate;
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my ($open, $close) = ('', '');
    if ($flags{-htmlClassMap} && (my $class = $flags{-htmlClassMap}{ref $self})) {
	($open, $close) = ("<div class=\"$class\">", "</div>");
    }
    my @a;
    if (!$flags{-brief}) {
	@a = $self->{ATTRIBUTION}->toString(%flags);
    }
    if (wantarray) {
	return $flags{-outputMode} eq 'n3' ? 
	    (' a :Bindings ; ', 
	     &DecorateArray(' :repr {{ ', '         ', '', ' }', $self->{BODY}->toString(%flags)), 
	     '         => ', 
	     &DecorateArray('        { ', '         ', '', ' }} ;', $self->{HEAD}->toString(%flags)), 
	     &DecorateArray(' :accordingTo ', '              ', '', '', @a)) : 
	     &DecorateArray("${open}fwrule ", '       ', '', $close, 
			    ($self->{BODY}->toString(%flags), 
			     $self->{HEAD}->toString(%flags), 
			     &DecorateArray('   -->', '             ', '', '', @a)));
    } else {
	my $aStr = @a ? ' '.join (' ', @a) : '';
	return 'fwrule '.$self->{BODY}->toString(%flags).' '.
	    $self->{HEAD}->toString(%flags).$aStr;
    }
}
sub getBody {$_[0]->{BODY}}
sub getHead {$_[0]->{HEAD}}

package W3C::Rdf::AlgaeCompileTree::Clear;
sub new {
    my ($proto, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    return $self;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
    $resultSet->clear(); # = new W3C::Rdf::ResultSet(-atomDictionary => $self->{-atomDictionary});
    my $labels = $self->{ALGAE2}->getLabels;
    splice (@$labels, 0, @$labels);
    #my $collects = $self->{ALGAE2}->getCollects;
    #splice (@$collects, 0, @$collects);
    $self->{ALGAE2}{-namespaceHandler}->clear;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return 'clear'; #  \'('.join (' ', map {$_->toString(%flags)} @{$self->{NODES}}).')';
}

package W3C::Rdf::AlgaeCompileTree::Collect;
sub new {
    my ($proto, $nodes, $distinct, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{NODES} = $nodes;
    $self->{DISTINCT} = $distinct;
    $self->{OFFSET} = undef;
    $self->{LIMIT} = undef;
    $self->{ORDER} = undef;
    return $self;
}
sub offset {
    my ($self, $offset) = @_;
    $self->{OFFSET} = $offset;
}
sub limit {
    my ($self, $limit) = @_;
    $self->{LIMIT} = $limit;
}
sub order {
    my ($self, $order) = @_;
    $self->{ORDER} = $order;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
    foreach my $atom (@{$self->{NODES}}) {
	$atom->addSelect();
    }
#    my $collects = $self->{ALGAE2}->getCollects;
#    push (@$collects, @{$self->{NODES}});
}
sub delayedEvaluate {
    my ($self, $resultSet) = @_;
    if ($self->{DISTINCT} || 
	defined $self->{OFFSET} || 
	defined $self->{LIMIT} || 
	$self->{ORDER}) {
	my $orderBy = $self->{ORDER} || [map {[$_, 1]} @{$self->{NODES}}];
	$resultSet->trim($self->{OFFSET}, $self->{LIMIT}, $orderBy, $self->{DISTINCT}, $self->{ALGAE2}, $self->{DISTINCT} && !$self->{ORDER} ? 1 : 0);
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $nodeStr = join (' ', map {$_->toString(%flags)} @{$self->{NODES}});
    return "collect ($nodeStr)";
}

package W3C::Rdf::AlgaeCompileTree::CollectStar;
sub new {
    my ($proto, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = {};
    bless ($self, $class);
    $self->{PARMS} = [@actionParms];
    return $self;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
    $self->{RESULT_SET} = $resultSet;
}
sub expandCollects {
    my ($self) = @_;
    my @symbols = $self->{RESULT_SET}->getSymbols();
    return map {new W3C::Rdf::AlgaeCompileTree::Var($_, 1, @{$self->{PARMS}})} @symbols;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return "collect (*)";
}

package W3C::Rdf::AlgaeCompileTree::SPARQLAsk;
sub new {
    my ($proto, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new([], 0, @actionParms);
    return $self;
}
sub delayedEvaluate {
    my ($self, $resultSet) = @_;
    $self->SUPER::delayedEvaluate($resultSet);
    $resultSet->testTrue(1);
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return "ask";
}

package W3C::Rdf::AlgaeCompileTree::Describe;
sub new {
    my ($proto, $nodes, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new($nodes, undef, @actionParms);
    return $self;
}
sub delayedEvaluate {
    my ($self, $resultSet) = @_;
    foreach my $atom (@{$self->{NODES}}) {
	$self->{ALGAE2}->bNodeClosure($resultSet, $atom->lookfor()); # !!! needs to walk rows
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $nodeStr = join (' ', map {$_->toString(%flags)} @{$self->{NODES}});
    return "describe ($nodeStr)";
}

package W3C::Rdf::AlgaeCompileTree::DescribeStar;
sub delayedEvaluate {
    my ($self, $resultSet) = @_;
    my @symbols = $self->{RESULT_SET}->getSymbols();
    for (my $i = 0; $i < @symbols; $i++) {
	$self->{ALGAE2}->bNodeClosure($resultSet, \ $i);
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return "describe (*)";
}

package W3C::Rdf::AlgaeCompileTree::Host;
sub new {
    my ($proto, $nodes, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{NODES} = $nodes;
    return $self;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
#    $resultSet->skipUsedColumns;
    my $hostables = $self->{ALGAE2}->getHostSymbols;
    foreach my $node (@{$self->{NODES}}) {
	$hostables->{$node->toString} = $node;
    }
}
# Here's sort of what you'd need to do the dalayedEval version of Host.
sub delayedEvaluateNUKE {
    my ($self, $resultSet) = @_;
    foreach my $atom (@{$self->{NODES}}) {
	my $newId = $self->{ALGAE2}{-atomDictionary}->getUri($self->{ALGAE2}->getNextHostID);
	$self->{DB}->changeId(undef, $atom, $newId);
	$resultSet->changeId($atom, $newId);
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return 'collect \'('.join (' ', map {$_->toString(%flags)} @{$self->{NODES}}).')';
}

# The Requilre object is only useful for serializing itself. It does no useful
# evaluation as the actual enforcement of the require directive happens in the
# Algae2 object.
package W3C::Rdf::AlgaeCompileTree::Require;
use W3C::Util::Exception;
sub new {
    my ($proto, $uri, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{URI} = $uri;
    return $self;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $uriStr = $self->{URI}->toString(%flags);
    return "require $uriStr";
}

package W3C::Rdf::AlgaeCompileTree::Slurp;
sub new {
    my ($proto, $src, $parms, $optDbSpec, $loader, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    if (!$loader) {
	&throw(new W3C::Util::Exception(-message => 'slurp needs a loader.'));
    }
    $self->{SOURCE} = $src;
    $self->{PARMS} = $parms;
    $self->{DB_SPEC} = $optDbSpec;
    $self->{LOADER} = $loader;
    return $self;
}
sub immediateEvaluate {
    my ($self, $resultSet) = @_;
    my $parms = $self->{PARMS};
    my $rdfApp = $self->{LOADER};
    my $url = $self->{SOURCE}->getUrl;

    # Could add IfNewThan semantics here.
    my $inputSource = &W3C::Rdf::RdfApp::getInputSource($url, $parms);
    my $attrib = $rdfApp->makeInputAttribution($inputSource->getPublicId());
    $self->{ALGAE2}{-rdfDB}->clearAttribution($attrib);

    if ($parms->{-printData}) {
	my $handle = $parms->{-printData};
	print $handle $inputSource->getByteStream;
    }
    my $lang = $parms->{-inputLang} ? $parms->{-inputLang}->getString : 
	$inputSource->getContentType();
    if (!defined $lang || $lang eq 'application/xml') {
	$lang = $inputSource->guessContentType();
    }
    my $origDB = $self->{ALGAE2}{-rdfDB};
    if ($self->{DB_SPEC} && $origDB != $self->{DB_SPEC}) {
	$self->{ALGAE2}{-rdfDB} = $self->{DB_SPEC};
    }
    my $text = $inputSource->getByteStream();
    &utf8::decode($text);
    $rdfApp->parse($text, 
		   $inputSource->getPublicId(), 
		   $lang, $self->{ALGAE2});
    if ($self->{DB_SPEC} && $origDB != $self->{DB_SPEC}) {
	$self->{ALGAE2}{-rdfDB} = $origDB;
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $dbStr = ''; #!!! $self->{DB_SPEC} ? $self->{DB_SPEC}->toString.' ' : '';
    my $sourceStr = $self->{SOURCE}->toString;
    my $parmsStr = ''; #!!! ($self->{PARMS} ? join (' ', %{$self->{PARMS}}) : '');
    return "slurp $sourceStr $dbStr ($parmsStr)";
}

# TriplesActions
package W3C::Rdf::AlgaeCompileTree::TriplesAction;
use W3C::Util::Exception;
use W3C::Util::ArrayUtils qw(&DecorateArray);
my $TriplesActions = {};
sub new {
    my ($proto, $decls, $optDbSpec, $defaultDB, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $TriplesActions->{$class}{$decls}{$optDbSpec}{$defaultDB};
    if (!$self) {
	$self = $class->SUPER::new(@actionParms);
	$self->{DECLS} = $decls;
	$self->{DB_SPEC} = $optDbSpec;
	$self->{DEF_DB} = $defaultDB;
	$TriplesActions->{$class}{$decls}{$optDbSpec}{$defaultDB} = $self;
    }
    return $self;
}
sub getDB {
    my ($self) = @_;
    return $self->{DB_SPEC} ? $self->{DB_SPEC} : $self->{DEF_DB};
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $dbStr = $self->{DB_SPEC} && $self->{DB_SPEC}{-name} ? 
	$self->{DB_SPEC}{-name}.' ' :
	'';
    my $leadStr = $flags{-outputMode} eq 'n3' ? "" : $self->getActionName."$dbStr(";
    my @declStrs = $self->{DECLS}->toString(%flags);
    if (wantarray) {
	my $indent = ' ' x (length($leadStr));
	return &DecorateArray($leadStr, $indent, '', $flags{-outputMode} eq 'n3' ? '' : ')', @declStrs);
    } else {
	my $declStr = join (' ', @declStrs);
	return $leadStr.$declStr.')';
    }
#    return $self->getActionName." '($dbStr\n".join ("\n", map {' '.$_->toString} @{$self->{DECLS}}).')';
}
sub getCNF {$_[0]->{DECLS}->toCNF}
sub getVars {
    my ($self) = @_;
    return $self->{DECLS}->getVars();
}
sub assignVarIndexes {
    my ($self, $resultSet, $create) = @_;
    $self->{DECLS}->assignVarIndexes($resultSet, $create);
}

package W3C::Rdf::AlgaeCompileTree::Ask;
sub evaluateQTermAndConstraints {
    my ($self, $resultSet, $db, $modifier) = @_;
    if ($self->{DECLS}) {
	$self->getDB()->dbEvaluateQTerm($resultSet, $self->{DECLS}, $self->getDB());
#	$self->{DECLS}->evaluateQTermAndConstraints($resultSet, $db, $modifier);
    }
    if ($main::bnodeIsExt) {
	$resultSet->eliminateRedundantBNodes();
    }
}
sub getActionName {'ask'}
sub delayedEvaluate {
    my ($self, $resultSet) = @_;
#    $resultSet->atLeastOneRow;
    if ($self->{DECLS}) {
	$self->getDB()->dbEvaluateQTerm($resultSet, $self->{DECLS}, $self->getDB());
    }
    $self->{ALGAE2}->dumpStuff('Query', $self->{ALGAE2}, $self->{DECLS});
    $self->{ALGAE2}->dumpStuff('QueryGraph', $self->{ALGAE2}, $self->{DECLS});
}
sub evaluateAssertion {
    my ($self, $resultSet, $db, $visited, $trigger, $attribution) = @_;
    my $uri = $self->{ALGAE2}{-atomDictionary}->getUri($self->{ALGAE2}->getNameBySource($self->getDB));
    my $attribution =  # $self->{-sourceAttribution};
	$self->{ALGAE2}{-atomDictionary}->getGroundFactAttribution($uri, undef, undef, undef);
    $self->{DECLS}->evaluateAssertion($resultSet, $self->{DB_SPEC} || $db, $visited, $trigger, $attribution);
}
sub evaluateDeletion {
    my ($self, $resultSet, $db, $visited, $trigger, $attribution) = @_;if (@_ < 4) {&throw}
    my $uri = $self->{ALGAE2}{-atomDictionary}->getUri($self->{ALGAE2}->getNameBySource($self->getDB));
    my $attribution =  # $self->{-sourceAttribution};
	$self->{ALGAE2}{-atomDictionary}->getGroundFactAttribution($uri, undef, undef, undef);
    $self->{DECLS}->evaluateDeletion($resultSet, $self->{DB_SPEC} || $db, $visited, $trigger, $attribution);
}
package W3C::Rdf::AlgaeCompileTree::Assert;
sub getActionName {'assert'}
sub delayedEvaluate {
    my ($self, $resultSet, $visited, $trigger, $attribution) = @_;if (@_ < 4) {&throw}
#    $resultSet->atLeastOneRow;
    my $ret = 0;
    if ($self->{DECLS}) {
	my @tmp = $self->getDB()->dbEvaluateAssertion($resultSet, $self->{DECLS}, $self->getDB(), $visited, $trigger, $attribution);
	$ret = scalar @tmp;
    }
    $resultSet->setSingletonValue($ret) if ($resultSet);
}

package W3C::Rdf::AlgaeCompileTree::Delete;
sub getActionName {'delete'}
sub delayedEvaluate {
    my ($self, $resultSet, $visited, $trigger, $attribution) = @_;if (@_ < 4) {&throw}
#    $resultSet->atLeastOneRow;
    my $ret = 0;
    if ($self->{DECLS}) {
	my @tmp = $self->getDB()->dbEvaluateDeletion($resultSet, $self->{DECLS}, $self->getDB(), $visited, $trigger, $attribution);
	$ret = scalar @tmp;
    }
    $resultSet->setSingletonValue($ret);
}

package W3C::Rdf::AlgaeCompileTree::AskAll;
use W3C::Util::ArrayUtils qw(&DecorateArray);
use W3C::Rdf::Atoms qw($ATTRIB_GroundFact $Value_NULL);
my $AskAllAtoms = {};
sub new {
    my ($proto, $decls, $sourceList, $var, $ctorFunc, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $TriplesActions->{$class}{$decls}{@$sourceList}{$var};
    if (!$self) {
	$self = $class->SUPER::new(@actionParms);
	$self->{DECLS} = $decls;
	$self->{Var} = $var;
	foreach my $source (@$sourceList) {
	    push (@{$self->{Asks}}, [$source, $ctorFunc->($source, $decls)]);
	}
	$TriplesActions->{$class}{$decls}{@$sourceList}{$var} = $self;
    }
    return $self;
}
sub delayedEvaluate {
    my ($self, $resultSet) = @_;

    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	foreach my $askPair (@{$self->{Asks}}) {
	    my ($name, $ask) = @$askPair;
	    my $atom = $self->{Var}->lookfor($row, $self->{ALGAE2}{-atomDictionary});
	    if ($atom == $Value_NULL) {
		next;
	    }
	    if (ref $atom eq 'SCALAR') {
		$atom = $row->get($$atom);
	    }
	    if (defined $atom && $atom->getUri ne $name) {
		next;
	    }
	    # !!! next if $self->{Var} bound and ne the source for the current ask.
	    my $miniResultSet = $row->makeResultSet;
	    $ask->delayedEvaluate($miniResultSet);
	    for (my $miniE = $miniResultSet->elements; $miniE->hasMoreElements;) {
		my $miniRow = $miniE->nextElement;
		# CONSTR_EVAL
		my $newRow = $row->duplicate;
		$newRow->assumeNewBindings($miniRow);
		# bind to this source
		if (!defined $atom) {
		    my $assign = $self->{ALGAE2}{-atomDictionary}->getUri($name);
		    $self->{Var}->absorb($assign, $newRow, $ask->{DB_SPEC});
		}
	    }
	}
	$row->eliminate;
    }
}
sub evaluateQTermAndConstraints {
    my ($self, $resultSet, $db, $modifier) = @_;
    $self->delayedEvaluate($resultSet);
}
sub nullOut {
    my ($self, $row) = @_;
    $self->{DECLS}->nullOut($row);
    if ($self->{Var}->isa('W3C::Rdf::AlgaeCompileTree::Var') && !defined $row->get($self->{Var}->varIndex)) {
	$self->{Var}->absorb($Value_NULL, $row);
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $dbStr = $self->{DB_SPEC} && $self->{DB_SPEC}{-name} ? 
	$self->{DB_SPEC}{-name}.' ' :
	'';
    my $leadStr = $flags{-outputMode} eq 'n3' ? "" : $self->getActionName."$dbStr(";
    my @declStrs = $self->{DECLS}->toString(%flags);
    if (wantarray) {
	my $indent = ' ' x (length($leadStr));
	return &DecorateArray($leadStr, $indent, '', $flags{-outputMode} eq 'n3' ? '' : ')', @declStrs);
    } else {
	my $declStr = join (' ', @declStrs);
	return $leadStr.$declStr.')';
    }
}

package W3C::Rdf::AlgaeCompileTree::Thing;
use W3C::Util::Exception;
sub new {
    my ($proto, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    $exprParms[0] || &throw(new W3C::Util::Exception(-message => "Bad exprParms (@exprParms) for $class baseclass Thing"));
    my $self = {ALGAE2 => $exprParms[0]->YYData->{ALGAE2}, 
		PARSER => $exprParms[0], 
		LASTPOS => $exprParms[0]->YYData->{my_LASTPOS}};
    bless ($self, $class);
    return $self;
}
sub NPnew {
    my ($proto, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    $exprParms[0] || &throw(new W3C::Util::Exception(-message => "Bad exprParms (@exprParms) for $class baseclass Thing"));
    my $self = {ALGAE2 => $exprParms[0], PARSER => undef, LASTPOS => undef};
    bless ($self, $class);
    return $self;
}

sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return "!!! $self no toString defined";
}

sub val {
    my ($self, $triple, $premise, $row) = @_;
    &throw(new W3C::Util::NotImplementedException(-object => $self));
}

package W3C::Rdf::AlgaeCompileTree::GraphPattern;
use W3C::Util::Exception;

sub new {
    my ($proto, $elements, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{ELEMENTS} = $elements;
    return $self;
}
sub evaluateQTermAndConstraints {
    my ($self, $resultSet, $db, $modifier) = @_;
    if ($self->{ELEMENTS}) {
	$self->{ELEMENTS}->evaluateQTermAndConstraints($resultSet, $db, $modifier);
    }
    if ($main::bnodeIsExt) {
	$resultSet->eliminateRedundantBNodes();
    }
}
sub setLastConstraints {
    my ($self, $constraints) = @_;
    return $self->{ELEMENTS} ? $self->{ELEMENTS}->setLastConstraints($constraints) : 1;
}
sub nullOut {$_[0]->{ELEMENTS}->nullOut($_[1])}
sub toDot {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return $self->{ELEMENTS}->toDot(%flags);
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my @ret = '{ ';
    push (@ret, $self->{ELEMENTS}->toString(%flags));
    push (@ret, ' }');
    return wantarray ? @ret : join('', @ret);
}

package W3C::Rdf::AlgaeCompileTree::GraphPatternElement;
use W3C::Util::Exception;

sub new {
    my ($proto, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{CONSTRAINTS} = [];
    return $self;
}

sub nestleConstraints {
    my ($self) = @_;
#    print "---\n", $self->toString(), "\n---\n";
#    $self->setLastConstraints($self->getConstraints());
}

sub setLastConstraints {
    my ($self, $constraints) = @_;

    push (@{$self->{CONSTRAINTS}}, @$constraints); # !!! hack until i get the algorithm worked out.
    return 1;
}
sub evaluateQTermAndConstraints {
    my ($self, $resultSet, $db, $modifier) = @_;
    my $handle;
    if (@{$self->{CONSTRAINTS}}) {
	$handle = $resultSet->getProofStreamHandle();
    }
    $self->evaluateQTerm($resultSet, $db, $modifier);
    if (@{$self->{CONSTRAINTS}}) {
	$self->evaluateConstraints($resultSet, $handle);
    }
}
sub evaluateConstraints {
    my ($self, $resultSet, $handle) = @_;
    # evalulate constraints CONSTR_EVAL
    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	my $passed = 1;
      CONSTRAINT:
	foreach my $constraint (@{$self->{CONSTRAINTS}}) {
	    my $statements = $row->forgetProofStreamStatements($handle);
	    foreach my $triple (@$statements) {
		eval {
		    my $res = $constraint->val($triple, undef, $row);
		    if (!$res || ($res->isa('W3C::Rdf::String') && !$res->getString)) {
			$passed = 0;
			last CONSTRAINT;
		    }
		}; if ($@) {if (my $ex = &catch('W3C::Util::SafeEvaluationException')) {
		    $passed = 0;
		    last CONSTRAINT;
		} else {
		    &throw();
		}}
	    }
	}

	if (!$passed) {
	    $row->eliminate;
	}
    }
}

package W3C::Rdf::AlgaeCompileTree::Decl;
use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($Value_NULL);
use vars qw($DISJUNCTION $NEGATION $OUTER);
($DISJUNCTION, $NEGATION, $OUTER) = ($W3C::Rdf::AlgaeCompileTree::DISJUNCTION, $W3C::Rdf::AlgaeCompileTree::NEGATION, $W3C::Rdf::AlgaeCompileTree::OUTER);
sub new {
    my ($proto, $parts, $constraints, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{PARTS} = $parts;
    $self->{CONSTRAINTS} = $constraints;
    return $self;
}
sub NPnew {
    my ($proto, $parts, $constraints, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::NPnew(@exprParms);
    $self->{PARTS} = $parts;
    $self->{CONSTRAINTS} = $constraints;
    return $self;
}
sub setLastConstraints999 {
    my ($self, $constraints) = @_;
    $self->{CONSTRAINTS} = $constraints;
    # Accept the constraints.
    return 1;
}
sub addLastConstraints {
    my ($self, $constraints) = @_;
    if ($self->{CONSTRAINTS}) {
	push (@{$self->{CONSTRAINTS}}, $constraints);
    } else {
	$self->{CONSTRAINTS} = [$constraints];
    }
    # Accept the constraints (for parallelism with set...).
    return 1;
}
sub val999 { # @@@ could be used if a triple meant something in a constraint
    my ($self, $triple, $premise, $row) = @_;
    return $self->{PARTS}; # !!!
}
sub arity {3}
sub getSlot {$_[0]->{PARTS}[$_[1]]}
sub evaluateAssertion {
    my ($self, $resultSet, $db, $visited, $trigger, $attribution) = @_;
    my @insertions = $self->assertedTriples($resultSet, $db, $visited, $trigger, $attribution);
    foreach my $insertion (@insertions) {
	my ($triple, $reified) = @$insertion;
	push (@$reified, $db->addTriple($triple, $attribution));
	my $statement = $db->applyRules([$triple], $triple, $visited, $attribution);
	1;#my $statement = $db->applyRules($reified, $triple);
    }
    return @insertions;
}
sub assertedTriples {
    my ($self, $resultSet, $db, $visited, $trigger, $attribution) = @_; # !!! nuke $db if possible
    my @insertions;
    if ($self->_allStatic()) {
	push (@insertions, $self->_assertDecl(undef, $db, $visited, $attribution));
    } elsif (!$resultSet->isFresh()) {
	for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	    my $row = $e->nextElement;
	    # print $row->toString,"\n";
	    my $substAttrib = $self->{ALGAE2}{-atomDictionary}->getInferenceAttribution($attribution, $row->getProofDB(), {$row->getBindings()});
	    if (my $asserted = $self->_assertDecl($row, $db, $visited, $substAttrib)) {
		push (@insertions, $asserted);
	    }
	}
    }
    return @insertions;
}
sub _allStatic {
    my ($self) = @_;
    foreach my $part (@{$self->{PARTS}}) {
	if (!$part->isa('W3C::Rdf::AlgaeCompileTree::StaticPOS')) {
	    return 0;
	}
    }
    return 1;
}
sub _assertDecl {
    my ($self, $row, $db, $visited, $attribution) = @_;
    my @statementParms = ();
    for (my $iParm = 0; $iParm < 4; $iParm++) {
	my $atom = $iParm < $self->arity ? 
	    $self->getSlot($iParm)->lookfor($row, $self->{ALGAE2}{-atomDictionary}) : 
	    undef;
	if (ref $atom eq 'SCALAR') {
	    $atom = $row->get($$atom);
	}
	if ($atom == $Value_NULL) {
	    return undef;
	}
	push (@statementParms, $atom);
    }
    # at this time, uri2Attribution is not defined in any db.
    #$self->{ALGAE2}->getSourceAttribution; # !!! use ATTRIB
    $statementParms[4] = $self->arity > 4 ? $db->uri2Attribution($self->[4]) : $attribution;

    # Ideally, we would create a statement and add it to the database.
    # The problem is that the tests need to have a statement to work on.
    # But those tests my keep the statement from being created. So we
    # create the statement, try the tests, and then delete it if the tests
    # indicated it should not be created.
    # Following is a bit of code that recreates the following statement:
    # my ($reified, $triple) = $db->createStatement(@statementParms);
    my $triple;
    my $pendingException = undef;
    eval {
	my ($p, $s, $o, $r, $a) = @statementParms;
	eval {
	    $triple = $self->{ALGAE2}{-atomDictionary}->getStatement($p, $s, $o, $r, $a);
	}; if ($@) {&throw();}
    }; if ($@) {if (my $ex = &catch('W3C::Rdf::BadlyFormedTripleException')) {
	$triple = $ex->getTriple;
	$pendingException = $ex;
    } elsif (my $ex = &catch('W3C::Util::Exception')) {
	&throw($ex);
    } else {
	die $@;
    }}

    if (exists $visited->{$triple}{$attribution}) { # maybe if $why ? {$why->[0]}{$why->[1]}
	return;
    }
    $visited->{$triple}{$attribution} = undef; # {$why->[0]}{$why->[1]}
    my $reified = $db->reify($triple, $statementParms[3]);

    # evalulate constraints CONSTR_EVAL
    if ($self->{CONSTRAINTS}) {
	foreach my $constraint (@{$self->{CONSTRAINTS}}) {
	    my $res = $constraint->val($triple, $self, $row);
	    if (!$res || ($res->isa('W3C::Rdf::String') && !$res->getString)) {
		return;
	    }
	}
    }

    if ($pendingException) {
	&throw($pendingException);
    }

    return [$triple, $reified];
}
sub evaluateDeletion {
    my ($self, $resultSet, $db, $visited, $trigger, $attribution) = @_;
    my @insertions = $self->assertedTriples($resultSet, $db, $visited, $trigger, $attribution);
    foreach my $insertion (@insertions) {
	my ($triple, $reified) = @$insertion;
	push (@$reified, $db->removeTriple($triple));
#	my $statement = $db->applyRules([$triple], $triple, $visited, $attribution);
	1;#my $statement = $db->applyRules($reified, $triple);
    }
    return @insertions;
}
sub evaluateQTermAndConstraints {
    my ($self, $resultSet, $db, $modifier) = @_;
    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	my @tmp = $self->_matchDecl($row, $db);

	# evalulate constraints CONSTR_EVAL
	if ($self->{CONSTRAINTS}) {
	    foreach my $constraint (@{$self->{CONSTRAINTS}}) {
		for (my $iT = 0; $iT < @tmp; $iT++) {
		    my $passed = 1;
		    eval {
			my $res = $constraint->val($tmp[$iT], $self, $row);
			if (!$res || ($res->isa('W3C::Rdf::String') && !$res->getString)) {
			    $passed = 0;
			}
		    }; if ($@) {if (my $ex = &catch('W3C::Util::SafeEvaluationException')) {
			$passed = 0;
		    } else {
			&throw();
		    }}

		    if (!$passed) {
			splice (@tmp, $iT, 1);
			--$iT;
		    }
		}
	    }
	}

	# absorb the results into the data set
	# comments assume changeing
	# [1 1] [s1 s2]
	# [2 4] [s4 s5]
	# [3 9] [s7 s8]
	# to
	# [1 1 1] [s1 s2 s3]
	# [2 4 8] [s4 s5 s6]
	# [3 9 27] [s7 s8 s9]
	if (@tmp) {
	    foreach my $triple (@tmp) {
		# build a new array of results (and supporting statements) in a new array
		# This could be done with an array splice, but it's less efficient and less portable to C/Java.

		# Next results start with current row ([2, 4]).
		#  and current statements ([s4 s5]).
		my $newRow = $row->duplicate;
		# Add this statement (s6) to the proofs ==> ([s4 s5 s6]).
		if ($self->{ALGAE2}{-flags}->{-lowLevelStatements} && @{$self->{ALGAE2}{-flags}->{-lowLevelStatements}}) {
		    my $statements = shift @{$self->{ALGAE2}{-flags}->{-lowLevelStatements}};
		    $newRow->addProofs($statements);
		} else {
		    $newRow->addProofs([$triple]);
		}
		# Take results (8) from this statement (s6) => ([2 4 8]).
		for (my $i = 0; $i < $self->arity; $i++) {
		    my $absorbed = $triple->getPosition($i);
		    if (UNIVERSAL::isa($self->getSlot($i), 'W3C::Rdf::AlgaeCompileTree::Members')) {
			my $listElements = $db->listsFrom($absorbed, undef);
			for (my $j = 0; $j < @$listElements; $j++) {
			    $self->getSlot($i)->absorb($listElements->[$j], $newRow, $db);

			    # Make new rows for all but the already-allocated first row entry.
			    if ($j < @$listElements-1) {
				$newRow = $row->duplicate;
				$newRow->addProofs([$triple]); # !!! wrong triple -- enhance listsFrom results
			    }
			}
		    } else {
			$self->getSlot($i)->absorb($absorbed, $newRow, $db);
		    }
		}
	    }
	    $row->eliminate;
	} elsif ($modifier & $OUTER && 0) {
	    # keep row
	    # assign NULLs to otherwise unassigned variable slots
	    for (my $i = 0; $i < $self->arity; $i++) {
		my $part = $self->getSlot($i);
		if ($part->isa('W3C::Rdf::AlgaeCompileTree::Var') && !defined $row->get($part->varIndex)) {
		    $part->absorb($Value_NULL, $row);
		}
	    }
	} else {
	    $row->eliminate;
	}
    }
}

# nullOut -- Set all referenced unset variables to NULL in the result set.
#            This keeps nested optionals from binding variables when the
#            parent optional has assumed a null binding for that variable. 
sub nullOut {
    my ($self, $row) = @_;
    for (my $i = 0; $i < $self->arity; $i++) {
	my $part = $self->getSlot($i);
	if ($part->isa('W3C::Rdf::AlgaeCompileTree::Var') && !defined $row->get($part->varIndex)) {
	    $part->absorb($Value_NULL, $row);
	}
    }
}

# assumeConstraint -- Assume a constraint if the constraint has all
#                     variables bound in this decl.
sub _matchDecl {
    my ($self, $row, $db) = @_;
    my $lookfor = [];
    if (!$self->{ALGAE2}{-flags}->{-lowLevelStatements}) {
	$self->{ALGAE2}{-flags} = {%{$self->{ALGAE2}{-flags}}, -lowLevelStatements => []};
    }
    my $flags = {%{$self->{ALGAE2}{-flags}}};
    for (my $i = 0; $i < $self->arity; $i++) {
	my $slot = $self->getSlot($i);
	my $atom = $slot->lookfor($row, $self->{-atomDictionary});
	if ($atom == $Value_NULL) {
	    return ();
	}
	if (ref $atom eq 'SCALAR') {
	    $atom = $row->get($$atom);
	}
	push (@$lookfor, $atom);
    }
    my @ret = $db->triplesMatching(undef, [$lookfor], $flags);
    if (@ret < $self->{-minimumRowSolution}) {
	my $flags = {-minimumRowSolution => $self->{-minimumRowSolution}};
	$self->minimumRowSolutionMethod($self, $flags, \@ret, $row, $lookfor);
    }

    # trim for cases like (dc:title dc:title "title")
    for (my $i = 0; $i < $self->arity - 1; $i++) {
	for (my $j = $i+1; $j < $self->arity; $j++) {
	    if ($self->getSlot($i)->matchingIntangible($self->getSlot($j))) {
		for (my $iT = 0; $iT < @ret; ++$iT) {
		    if ($ret[$iT]->getPosition($i) != $ret[$iT]->getPosition($j)) {
			splice (@ret, $iT, 1);
			--$iT;
		    }
		}
	    }
	}
    }

    return @ret;
}

sub toCNF {$_[0]}

# @@@ not operational right now
sub minimumRowSolutionMethod {
    my ($self, $term, $flags, $initialSolutions, $row, $lookfor, $db, $view, $querySets) = @_;
    # note - will want to vary constants but not bound variabels for tab completion.
    print STDERR 'failed: '.$term->getSlot(0)->getExpr->toString."\n";

    my ($contants , $boundVars, $unboundVars) = (0, 0, 0);
    for (my $i = 0; $i < $term->arity; $i++) {
	if ($term->getSlot($i)->isa('W3C::Rdf::Algae::ConstantQueryPiece')) {
	    $contants++;
	} elsif ($term->getSlot($i)->isa('W3C::Rdf::Algae::VariableQueryPiece')) {
	    if ($lookfor->[$i]) {
		$boundVars++;
	    } else {
		$unboundVars++;
	    }
	}
    }

    # check variations on new variables
    for (my $unbind = 1; $unbind < $boundVars + $contants; $unbind++) {
	# try substituting $unbind contants
	for (my $i = 0; $i < $term->arity; $i++) {
	    if ($term->getSlot($i)->isa('W3C::Rdf::Algae::ConstantQueryPiece')) {
		my $tmp = $lookfor->[$i];
		$lookfor->[$i] = undef;
		@$initialSolutions = $db->triplesMatching($view, [$lookfor], $flags);
		for (my $iWorky = 0; $iWorky < @$initialSolutions; $iWorky++) {
		    my ($try, $place) = 
			$i == 0 ? ($initialSolutions->[$iWorky]->getPredicate, 'predicate') : $i == 1 ? ($initialSolutions->[$iWorky]->getSubject, 'subject') : $i == 2 ? ($initialSolutions->[$iWorky]->getObject, 'object') : (undef, undef);
		    $try = $try->toString;
		    print STDERR "trying $place $try\n";
		}
	    }
	}
    }
    if ($flags && @$initialSolutions < $flags->{-minimumRowSolution}) {
	my @bindings;
	foreach my $term ($querySets->getTerms) {
	    for (my $j = 0; $j < $term->arity; $j++) {
		my $qp = $term->[$j];
		if ($qp->isa('W3C::Rdf::Algae::VariableQueryPiece')) {
		    my $column = $qp->varIndex;
		    my $sym = $qp->symbol;
		    my $val = $row->[$column];
		    if (defined $val) {
			$val = $val->toString;
		    } else {
			last;
		    }
		    $bindings[$column] = "?$sym $val";
		}
	    }
	}
	print STDERR "dropping row:\n    ".join("\n    ", @bindings)."\n";
    }
}

sub toGraph {
    my ($self, $or, $not, $opt) = @_;
    my @pParts;
    if ($or) {push @pParts, '||'}
    if ($not) {push @pParts, '!'}
    if ($opt) {push @pParts, '~'}
    push (@pParts, $self->{PARTS}[0]->toString(undef, undef));
    my $s = $self->{PARTS}[1]->toString(undef, undef);
    $s =~ s/(\\(?!n)|\"|<|>)/\\$1/gx;
    my $o = $self->{PARTS}[2]->toString(undef, undef);
    $o =~ s/(\\(?!n)|\"|<|>)/\\$1/gx;
    if ($self->{CONSTRAINTS}) {
	push (@pParts, join ("\\n", map {$_->toString(undef, undef)} @{$self->{CONSTRAINTS}}));
    }
    map {s/(\\(?!n)|\"|<|>)/\\$1/gx} @pParts;
    return "\"$s\" -> \"$o\" [label=\"".join (' ', @pParts)."\"];\n";
}

sub toDot {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my @parts;
    foreach my $i (1, 0, 2) {
	push (@parts, $self->{PARTS}[$i]->toString(%flags));
    }
    if ($self->{CONSTRAINTS}) {
	push (@parts, join ("\\n", map {$_->toString(%flags)} @{$self->{CONSTRAINTS}}));
    }
    map {s/(\\(?!n)|\"|<|>)/\\$1/gx} @parts;
    return "\"$self\" [shape=record label=\"".join ('|', @parts)."\"];\n";
}

sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $ret = join (' ', map {$_->toString(%flags)} 
		    ($self->{PARTS}[1], 
		     $self->{PARTS}[0], 
		     $self->{PARTS}[2]));
    if ($self->{CONSTRAINTS}) {
	$ret .= ' '.join('', map {'{'.$_->toString(%flags, -parentPrec => $MAX_PREC).'}'} @{$self->{CONSTRAINTS}});
    }
    return $ret;
}
sub getVars {
    my ($self) = @_;
    my %ret;
    for (my $i = 0; $i < 3; $i++) {
	my $part = $self->{PARTS}[$i];
	if (UNIVERSAL::isa($part, 'W3C::Rdf::AlgaeCompileTree::Var') && 
	    !UNIVERSAL::isa($part, 'W3C::Rdf::AlgaeCompileTree::NovelVar')) {
	    $ret{$part->symbol} = $part;
	}
    }
    return %ret;
}
sub assignVarIndexes {
    my ($self, $resultSet, $create) = @_;
    for (my $i = 0; $i < 3; $i++) {
	my $part = $self->{PARTS}[$i];
	if (UNIVERSAL::isa($part, 'W3C::Rdf::AlgaeCompileTree::Var')) {
	    $part->assignVarIndex($resultSet, $create);
	}
    }
}

package W3C::Rdf::AlgaeCompileTree::UnaryDecl;
sub new {
    my ($proto, $decl, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{DECL} = $decl;
    return $self;
}
sub getDecl {$_[0]->{DECL}}
sub nullOut {$_[0]->{DECL}->nullOut($_[1])}
sub toDot {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $opStr = $self->opStr;
    return "\"$self\" [label=\"$opStr\"];
\"$self\" -> \"$self->{DECL}\"
".$self->{DECL}->toDot(%flags);
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $opStr = $self->opStr;
    return $opStr.$self->{DECL}->toString(%flags);
}


package W3C::Rdf::AlgaeCompileTree::Negation;
use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($Value_NULL);
sub setLastConstraints999 {
    my ($self, $constraints) = @_;
    # $self->{CONSTRAINTS} = $constraints;
    # Decline the constraints.
    return 0;
}
sub evaluateQTerm {
    my ($self, $resultSet, $db, $modifier) = @_;

    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	my $miniResultSet = $row->makeResultSet;
	$self->{DECL}->evaluateQTermAndConstraints($miniResultSet, $db, $modifier);
	# CONSTR_EVAL ?
	my $miniE = $miniResultSet->elements;
	if ($miniE->hasMoreElements) {
	    # if there are unbound variables, we
	    #   push (@$nextResults, [@$row]);
	    #   push (@$nextStatements, [@$statements]);
	    # and make sure we don't get those bindings later...
	    #   for (my $i = 0; $i < $self->arity; $i++) {
	    #       $self->getSlot($i)->absorb($triple->getPosition($i), $nextResults, NOT!);
	    #   }
	    $row->eliminate;
	}
    }
}
sub toGraph {
    my ($self, $or, $not, $opt) = @_;
    $self->{DECL}->toGraph($or, !$not, $opt);
}
sub opStr {'!'}

package W3C::Rdf::AlgaeCompileTree::Option;
use W3C::Util::Exception;
use W3C::Util::ArrayUtils qw(&DecorateArray);
use W3C::Rdf::Atoms qw($Value_NULL);
use vars qw($DISJUNCTION $NEGATION $OUTER);
($DISJUNCTION, $NEGATION, $OUTER) = ($W3C::Rdf::AlgaeCompileTree::DISJUNCTION, $W3C::Rdf::AlgaeCompileTree::NEGATION, $W3C::Rdf::AlgaeCompileTree::OUTER);
sub setLastConstraints999 {
    my ($self, $constraints) = @_;
    # $self->{CONSTRAINTS} = $constraints;
    # Decline the constraints.
    return 0;
}
sub evaluateQTerm {
    my ($self, $resultSet, $db, $modifier) = @_;

    if (!$self->{DECL}) {
	return;
    }
    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	my $miniResultSet = $row->makeResultSet;
	$self->{DECL}->evaluateQTermAndConstraints($miniResultSet, $db, $modifier | $OUTER);
	# CONSTR_EVAL
	my $empty = 1;
	for (my $miniE = $miniResultSet->elements; $miniE->hasMoreElements;) {
	    $empty = 0;
	    my $miniRow = $miniE->nextElement;
	    my $newRow = $row->duplicate;
	    $newRow->assumeNewBindings($miniRow);
	}
	if ($empty) {
	    $self->{DECL}->nullOut($row);
	} else {
	    $row->eliminate;
	}
    }
}
sub toGraph {
    my ($self, $or, $not, $opt) = @_;
    $self->{DECL}->toGraph($or, $not, 1);
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    if ($flags{-outputMode}) {
	&throw(new W3C::Util::NotImplementedException(
			      -class => 'W3C::Rdf::AlgaeCompileTree::Option', 
			      -method => 'toString(-outputMode => "n3")'));
    }
    my $leadStr = UNIVERSAL::isa($self->{DECL}, 'W3C::Rdf::AlgaeCompileTree::Decl') ? '~' : '~(';
    my $tailStr = UNIVERSAL::isa($self->{DECL}, 'W3C::Rdf::AlgaeCompileTree::Decl') ? '' : ')';
    my @declStrs = $self->{DECL}->toString(%flags);
    if (wantarray) {
	my $indent = ' ' x (length($leadStr));
	return &DecorateArray($leadStr, $indent, '', $tailStr, @declStrs);
    } else {
	my $declStr = join (' ', @declStrs);
	return "$leadStr$declStr$tailStr";
    }
}
sub opStr {'~'}

package W3C::Rdf::AlgaeCompileTree::BinaryDecl;
use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($Value_NULL);
sub new {
    my ($proto, $left, $right, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{LEFT} = $left;
    #$left->toString(); # $$$ test
    $self->{RIGHT} = $right;
    #$right->toString(); # $$$ test
    return $self;
}
sub getLeft {$_[0]->{LEFT}}
sub getRight {$_[0]->{RIGHT}}
sub getDecls {($_[0]->{LEFT}, $_[0]->{RIGHT})}
sub nullOut {$_[0]->{LEFT}->nullOut($_[1]); $_[0]->{RIGHT}->nullOut($_[1])}

sub setLastConstraints999 {
    my ($self, $constraints) = @_;

    push (@{$self->{CONSTRAINTS}}, @$constraints); # !!! hack until i get the algorithm worked out.
    return 1;

    if ($self->{RIGHT}->setLastConstraints($constraints) || 
	$self->{LEFT}->setLastConstraints($constraints)) {
	# A lower construction accepted the constraint.
	return 1;
    } else {
	$self->{CONSTRAINTS} = $constraints;
	return 1;
    }
}

sub toDot {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $opStr = $self->opStr;
    return "\"$self\" [label=\"$opStr\"];
\"$self\" -> \"$self->{LEFT}\"  [label=\"l\"];
\"$self\" -> \"$self->{RIGHT}\"  [label=\"r\"];
".$self->{LEFT}->toDot(%flags)."
".$self->{RIGHT}->toDot(%flags);
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $opStr = $self->opStr(%flags);
    if (wantarray) {
	my @l = $self->{LEFT}->toString(%flags);
	$l[-1] .= " $opStr ";
	my @r = $self->{RIGHT}->toString(%flags);
	return (@l, @r);
    } else {
	return join (" $opStr ", map {$_->toString(%flags)} ($self->{LEFT}, $self->{RIGHT}));
    }
}
sub getVars {
    my ($self) = @_;
    return ($self->{LEFT}->getVars(), 
	    $self->{RIGHT}->getVars());
}
sub assignVarIndexes {
    my ($self, $resultSet, $create) = @_;
    $self->{LEFT}->assignVarIndexes($resultSet, $create);
    $self->{RIGHT}->assignVarIndexes($resultSet, $create);
}

package W3C::Rdf::AlgaeCompileTree::Conjunction;
use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($Value_NULL);
sub evaluateAssertion {
    my ($self, $resultSet, $db, $visited, $trigger, $attribution) = @_;
    return (
	$self->{LEFT}->evaluateAssertion($resultSet, $db, $visited, $trigger, $attribution), 
	$self->{RIGHT}->evaluateAssertion($resultSet, $db, $visited, $trigger, $attribution)
	);
}
sub assertedTriples {
    my ($self, $resultSet, $db, $visited, $trigger, $attribution) = @_; # !!! nuke $db if possible
    return ($self->{LEFT}->assertedTriples($resultSet, $db, $visited, $trigger, $attribution), 
	    $self->{RIGHT}->assertedTriples($resultSet, $db, $visited, $trigger, $attribution));
}

sub evaluateQTerm {
    my ($self, $resultSet, $db, $modifier) = @_;
    foreach my $decl ($self->{LEFT}, $self->{RIGHT}) {
	eval {
	    $decl->evaluateQTermAndConstraints($resultSet, $db, $modifier);
	}; if ($@) {
	    my $ex;
	    if ($ex = &catch('W3C::Rdf::RdfDBException')) {
		$self->{-errorHandler}->warning($ex);
	    } elsif ($ex = &catch('W3C::Util::Exception')) {
#		$self->{-errorHandler}->warning($ex);
		&throw($ex);
	    } else {
		&throw();
		$self->{-errorHandler}->error(new W3C::Util::PerlException);
	    }
	}
    }
}
sub toCNF {
    my ($self) = @_;
    return ($self->{LEFT}->toCNF, $self->{RIGHT}->toCNF);
}
sub toGraph {
    my ($self, $or, $not, $opt) = @_;
    $self->{LEFT}->toGraph($or, $not, $opt)."\n".$self->{RIGHT}->toGraph($or, $not, $opt)."\n";
}
sub opStr {
    my ($self, %flags) = @_;
    return $flags{-outputMode} eq 'n3' || $flags{-lang} eq 'SPARQL' ? '.' : '&&';
}

package W3C::Rdf::AlgaeCompileTree::ShortcutDisjunction;
use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($Value_NULL);
sub evaluateQTerm {
    my ($self, $resultSet, $db, $modifier) = @_;

    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	my $empty = 1;
	foreach my $term ($self->{LEFT}, $self->{RIGHT}) {
	    my $otherTerm = $term == $self->{LEFT} ? $self->{RIGHT} : $self->{LEFT};
	    my $miniResultSet = $row->makeResultSet;
	    $term->evaluateQTermAndConstraints($miniResultSet, $db, $modifier);
	    for (my $miniE = $miniResultSet->elements; $miniE->hasMoreElements;) {
		$empty = 0;
		my $miniRow = $miniE->nextElement;
		# CONSTR_EVAL
		my $newRow = $row->duplicate;
		$newRow->assumeNewBindings($miniRow);
		$otherTerm->nullOut($newRow);
	    }
	    last if (!$empty);
	}
	$row->eliminate;
    }
}
sub toGraph {
    my ($self, $or, $not, $opt) = @_;
    $self->{LEFT}->toGraph(1, $not, $opt)."\n".$self->{RIGHT}->toGraph(1, $not, $opt)."\n";
}
sub opStr {'||'}

package W3C::Rdf::AlgaeCompileTree::UnionDisjunction;
use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($Value_NULL);
sub evaluateQTerm {
    my ($self, $resultSet, $db, $modifier) = @_;

    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	foreach my $term ($self->{LEFT}, $self->{RIGHT}) {
	    my $otherTerm = $term == $self->{LEFT} ? $self->{RIGHT} : $self->{LEFT};
	    my $miniResultSet = $row->makeResultSet;
	    $term->evaluateQTermAndConstraints($miniResultSet, $db, $modifier);
	    for (my $miniE = $miniResultSet->elements; $miniE->hasMoreElements;) {
		my $miniRow = $miniE->nextElement;
		# CONSTR_EVAL
		my $newRow = $row->duplicate;
		$newRow->assumeNewBindings($miniRow);
		$otherTerm->nullOut($newRow);
	    }
	}
	$row->eliminate;
    }
}
sub toGraph {
    my ($self, $or, $not, $opt) = @_;
    $self->{LEFT}->toGraph(1, $not, $opt)."\n".$self->{RIGHT}->toGraph(1, $not, $opt)."\n";
}
sub opStr {'||'}

package W3C::Rdf::AlgaeCompileTree::UnionDisjunctionMerge;
use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($Value_NULL);
sub evaluateQTerm {
    my ($self, $resultSet, $db, $modifier) = @_;

    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	my $keepRow = 0;
	foreach my $term ($self->{LEFT}, $self->{RIGHT}) {
	    my $otherTerm = $term == $self->{LEFT} ? $self->{RIGHT} : $self->{LEFT};
	    my $miniResultSet = $row->makeResultSet;
	    $term->evaluateQTermAndConstraints($miniResultSet, $db, $modifier);
	    for (my $miniE = $miniResultSet->elements; $miniE->hasMoreElements;) {
		my $miniRow = $miniE->nextElement;
		if (my $foundRow = $row->getCousinWithBindings($miniRow)) {
		    $foundRow->assumeNewProofs($miniRow);
		    if ($foundRow == $row) {
			$keepRow = 1;
		    }
		} else {
		    # CONSTR_EVAL
		    my $newRow = $row->duplicate;
		    $newRow->assumeNewBindings($miniRow);
		    $otherTerm->nullOut($newRow);
		}
	    }
	}
	if (!$keepRow) {
	    $row->eliminate;
	}
    }
}
sub toGraph {
    my ($self, $or, $not, $opt) = @_;
    $self->{LEFT}->toGraph(1, $not, $opt)."\n".$self->{RIGHT}->toGraph(1, $not, $opt)."\n";
}
sub opStr {'||'}

package W3C::Rdf::AlgaeCompileTree::POS;
use W3C::Util::Exception;
sub lookfor {&throw(new W3C::Util::MethodNotImplementedException(-object => $_[0], -function => 'W3C::Rdf::AlgaeCompileTree::POS::lookfor'))}
sub absorb ($$$) {&throw(new W3C::Util::MethodNotImplementedException(-object => $_[0], -function => 'W3C::Rdf::AlgaeCompileTree::POS::absorb'))}
sub matchingIntangible ($$) {return undef;}

package W3C::Rdf::AlgaeCompileTree::StaticPOS;
sub lookfor {$_[0]->{INTERNED}}
sub val {$_[0]->{INTERNED}}
sub absorb ($$$) {}
sub matchingIntangible ($$) {return undef;}
sub addSelect {
    my ($self) = @_;
    $self->{ALGAE2}->addLabel($self->toString, $self);
}
sub symbol ($$) {return $_[0]->{CONST}}

package W3C::Rdf::AlgaeCompileTree::Literal;
sub new {
    my ($proto, $literal, $dt, $lang, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{CONST} = $literal;
    $self->{DT} = $dt;
    $self->{INTERNED_DT} = $dt ? $self->{ALGAE2}{-atomDictionary}->getUri($dt->getUrl) : undef;
    $self->{LANG} = $lang;
    $self->{UNINTERNED_LANG} = $lang ? $lang->{CONST} : undef;
    $self->{INTERNED} = $self->{ALGAE2}{-atomDictionary}->getString($literal, $self->{INTERNED_DT}, 'PLAIN', $self->{UNINTERNED_LANG});
    return $self;
}

sub NPnew {
    my ($proto, $literal, $dt, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::NPnew(@exprParms);
    $self->{CONST} = $literal;
    $self->{DT} = $dt;
    $self->{INTERNED_DT} = $dt ? $self->{ALGAE2}{-atomDictionary}->getUri($dt->getUrl) : undef;
    $self->{INTERNED} = $self->{ALGAE2}{-atomDictionary}->getString($literal, $self->{INTERNED_DT}, 'PLAIN');
    return $self;
}

sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return "\"$self->{CONST}\"";
}

package W3C::Rdf::AlgaeCompileTree::Num;
sub new {
    my ($proto, $literal, $dataType, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    return $class->SUPER::new($literal, $dataType,  undef, @exprParms);
}

sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return $self->{CONST};
}
#sub _binaryOp {
#    my ($self, $r, $op) = @_;
#    return new W3C::Rdf::AlgaeCompileTree::Num(&$op($self->{CONST}, $r->{CONST}), undef, $self->{PARSER});
#}
#sub multiply {$_[0]->_binaryOp($_[1], sub {$_[0] * $_[1]})}
#sub divide {$_[0]->_binaryOp($_[1], sub {$_[0] / $_[1]})}
#sub modulo {$_[0]->_binaryOp($_[1], sub {$_[0] % $_[1]})}
#sub plus {$_[0]->_binaryOp($_[1], sub {$_[0] + $_[1]})}
#sub minus {$_[0]->_binaryOp($_[1], sub {$_[0] - $_[1]})}

package W3C::Rdf::AlgaeCompileTree::Int;
sub new {
    my ($proto, $literal, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    $class->SUPER::new($literal, new W3C::Rdf::AlgaeCompileTree::Url('http://www.w3.org/2001/XMLSchema#integer',  undef, @exprParms), @exprParms);
}

package W3C::Rdf::AlgaeCompileTree::Decimal;
sub new {
    my ($proto, $literal, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    $class->SUPER::new($literal, new W3C::Rdf::AlgaeCompileTree::Url('http://www.w3.org/2001/XMLSchema#decimal', undef, @exprParms), @exprParms);
}

package W3C::Rdf::AlgaeCompileTree::Double;
sub new {
    my ($proto, $literal, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    $class->SUPER::new($literal, new W3C::Rdf::AlgaeCompileTree::Url('http://www.w3.org/2001/XMLSchema#double', undef, @exprParms), @exprParms);
}

package W3C::Rdf::AlgaeCompileTree::Boolean;
sub new {
    my ($proto, $literal, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    $class->SUPER::new($literal, new W3C::Rdf::AlgaeCompileTree::Url('http://www.w3.org/2001/XMLSchema#boolean',  undef, @exprParms), @exprParms);
}

package IRI;
@IRI::ISA = qw(URI);
sub _init
{
    my $class = shift;
    my($str, $scheme) = @_;
#   Must NOT punycode-ify, so commented out the following line:
#    $str =~ s/([^$uric\#])/$URI::Escape::escapes{$1}/go;
    $str = "$scheme:$str" unless $str =~ /^$URI::scheme_re:/o ||
                                 $class->_no_scheme_ok;
    my $self = bless \$str, $class;
    $self;
}

package W3C::Rdf::AlgaeCompileTree::UrlBase;
sub new {
    my ($proto, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{CONST} = '--- improper constructor ---';
    return $self;
}
sub NPnew {
    my ($proto, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::NPnew(@exprParms);
    $self->{CONST} = '--- improper constructor ---';
    return $self;
}
sub _setUrl {
    my ($self, $url) = @_;
    my $base = $self->{ALGAE2}->getSourceAttribution(1) ? 
	$self->{ALGAE2}->getSourceAttribution()->getSource()->getUri() : '';
#    &utf8::encode($url);
#    &utf8::encode($base);
    $URI::_generic::ISA[0] = 'IRI';
    my $uriOb = new URI::WithBase($url, $base)->abs()->as_string();
    $URI::_generic::ISA[0] = 'URI';
    $self->{CONST} = "$uriOb";
#    &utf8::decode($self->{CONST});
    $self->{INTERNED} = $self->{ALGAE2}{-atomDictionary}->getUri($self->{CONST});
}
sub getUrl {$_[0]->{CONST}}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
#    my ($ns, $prefix, $localName) = $self->{ALGAE2}{-namespaceHandler}->unmapNamespace($self->{CONST});
    my ($ns, $prefix, $localName);
    if (my $nsh = $flags{-namespaceHandler}) {
	($ns, $prefix, $localName) = $nsh->unmapNamespace($self->{CONST});
    }
    return defined $ns ? $prefix eq '' ? $localName : "${prefix}:$localName" : "<$self->{CONST}>";
}
sub interned {$_[0]->{INTERNED}}

package W3C::Rdf::AlgaeCompileTree::Url;
sub new {
    my ($proto, $url, $base, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    if ($base) {
	$url = new URI::WithBase($url, new URI($base->getUrl))->abs()->as_string();
    }
    $self->_setUrl($url);
    return $self;
}

sub NPnew {
    my ($proto, $url, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::NPnew(@exprParms);
    $self->_setUrl($url);
    return $self;
}

package W3C::Rdf::AlgaeCompileTree::DelayedQName;
use W3C::Util::Exception;
sub new {
    my ($proto, $prefix, $localName, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{PREFIX} = $prefix;
    $self->{LOCAL_NAME} = $localName;
    $self->{RESOLVED} = 0;
    return $self;
}
sub resolveNS {
    my ($self) = @_;
    eval {
	my ($ns, $localName, $prefix) = $self->{PARSER}->mapNamespace("$self->{PREFIX}:$self->{LOCAL_NAME}");
	$self->_setUrl("$ns$localName");
	$self->{RESOLVED} = 1;
    }; if ($@) {if (my $ex = &catch('W3C::Util::UnknownNamespaceException')) {
	my $newEx = new W3C::Util::CachedContextException(-str => $self->{PARSER}->YYData->{INPUT}, 
							  -pos => $self->{LASTPOS}, 
							  -contextID => $self->{PARSER}, 
							  -chainedException => $ex);
	$newEx->assumeStackTrace($ex);
	&throw($newEx);
    } else {
	&throw();
    }}
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return $self->{RESOLVED} ? "$self->{PREFIX}:$self->{LOCAL_NAME}" : "?$self->{PREFIX}?:$self->{LOCAL_NAME}"; # $self->SUPER::toString(%flags)
}

package W3C::Rdf::AlgaeCompileTree::QName;
sub new {
    my ($proto, $prefix, $localName, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new($prefix, $localName, @exprParms);
    $self->resolveNS();
    return $self;
}

package W3C::Rdf::AlgaeCompileTree::List;
use W3C::Util::Exception;
sub new {
    my ($proto, $var, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{VAR} = $var;
    return $self;
}

sub addSelect {
    my ($self) = @_;
    &throw(new W3C::Util::NotImplementedException());
    $self->{ALGAE2}->addLabel($self->{VARNAME}, $self->{VARINDEX});
}
sub varIndex () {
    my ($self) = @_;
    return $self->{VAR}->varIndex();
}
sub newSymbol () {
    &throw(new W3C::Util::NotImplementedException());
return $_[0]->{NEWSYMBOL}}

sub symbol ($$) {
    &throw(new W3C::Util::NotImplementedException());
return $_[0]->{VARNAME}}
sub lookfor ($$) {
    my ($self, $row, $atoms) = @_;
    return $self->{VAR}->lookfor($row, $atoms);
}

sub absorb ($$$) {
    my ($self, $absorbed, $row, $db) = @_;
    my $listElements = $db->listsFrom($absorbed, undef);
    # $absorbed = $self->{ALGAE2}->maybeHost($absorbed, $self);
    my $list = $self->{ALGAE2}{-atomDictionary}->createList($listElements);
    $row->set($self->varIndex, $list) if ($row); # may be undef for static asserts
    return $list;
}

sub matchingIntangible ($$) {
    my ($self, $against) = @_;
    &throw(new W3C::Util::NotImplementedException());
    if ($against->isa('W3C::Rdf::AlgaeCompileTree::Var')) {
	return $self->{VARNAME} eq $against->{VARNAME};
    } else {
	return undef;
    }
}

sub val {
    my ($self, $triple, $premise, $row) = @_;
    &throw(new W3C::Util::NotImplementedException());
    my $ret = $row->get($self->varIndex);
    if (defined $ret) {
	# Variable already bound in the row's result set.
	return $ret;
    }
    if (defined $premise) {
	# Extract variable's value from the premise.
	for (my $i = 0; $i < $premise->arity; $i++) {
	    my $pos = $premise->getSlot($i);
	    if ($pos->isa('W3C::Rdf::AlgaeCompileTree::Var') && 
		$pos->{VARNAME} eq $self->{VARNAME}) {
		return $triple->getPosition($i);
	    }
	}
	return undef;
    }
    # No way to resolve variable.
    &throw(new W3C::Rdf::UnmentionedVariableException(-var => $self->{VARNAME}));
}
sub assign {
    my ($self, $triple, $premise, $row, $value) = @_;
    &throw(new W3C::Util::NotImplementedException());
    $self->absorb($value, $row);
    return $value;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $str = $self->{VAR}->toString();
    return "list($str)";
    # return $self->{INTERNED}->toString;
}

package W3C::Rdf::AlgaeCompileTree::Members;
use W3C::Util::Exception;
sub new {
    my ($proto, $var, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{VAR} = $var;
    return $self;
}

sub varIndex () {
    my ($self) = @_;
    return $self->{VAR}->varIndex();
}
sub lookfor ($$) {
    my ($self, $row, $atoms) = @_;
    return $self->{VAR}->lookfor($row, $atoms);
}
sub absorb ($$$) {
    my ($self, $absorbed, $row, $db) = @_;
    $absorbed = $self->{ALGAE2}->maybeHost($absorbed, $self);
    $row->set($self->varIndex, $absorbed) if ($row); # may be undef for static asserts
    return $absorbed;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $str = $self->{VAR}->toString();
    return "members($str)";
    # return $self->{INTERNED}->toString;
}

package W3C::Rdf::AlgaeCompileTree::BNode;
sub new {
    my ($proto, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{INTERNED} = $self->{ALGAE2}{-atomDictionary}->createBNode($self->{ALGAE2}->getSourceAttribution);
    return $self;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return $self->{INTERNED}->toString(%flags);
}

package W3C::Rdf::AlgaeCompileTree::Var;
use W3C::Util::Exception;
sub new {
    my ($proto, $name, $create, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{VARNAME} = $name;
    $self->{NEWSYMBOL} = 0;
    my $resultSet = $self->{ALGAE2}->getResultSet;
    $self->assignVarIndex($resultSet, $create);
    return $self;
}
sub addSelect {
    my ($self) = @_;
    $self->{ALGAE2}->addLabel($self->{VARNAME}, $self);
}
sub varIndex () {return $_[0]->{VARINDEX}}
sub newSymbol () {return $_[0]->{NEWSYMBOL}}
sub assignVarIndex {
    my ($self, $resultSet, $create) = @_;
    $self->{VARINDEX} = $resultSet->getIndex($self->{VARNAME});
    if (!defined $self->{VARINDEX}) {
	if ($create) {
	    $self->{VARINDEX} = $resultSet->bindSymbol($self->{VARNAME});
	    $self->{NEWSYMBOL} = 1;
	} else {
	    &throw(new W3C::Util::Exception(-message => "no bindings for $self->{VARNAME}"));
	}
    }
}

sub symbol ($$) {return $_[0]->{VARNAME}}
sub lookfor ($$) {
    my ($self, $row, $atoms) = @_;
    return \ $self->varIndex;
    return $row->get($self->varIndex);
}

sub absorb ($$$) {
    my ($self, $absorbed, $row) = @_;
    $absorbed = $self->{ALGAE2}->maybeHost($absorbed, $self);
    $row->set($self->varIndex, $absorbed) if ($row); # may be undef for static asserts
    return $absorbed;
}

sub matchingIntangible ($$) {
    my ($self, $against) = @_;
    if ($against->isa('W3C::Rdf::AlgaeCompileTree::Var')) {
	return $self->{VARNAME} eq $against->{VARNAME};
    } else {
	return undef;
    }
}

sub FindOrMake999 {
    my ($name) = @_;
    my $ret = $CalcTree::VARS->{$name};
    if (!$ret) {
	$ret = new Var($name);
	$CalcTree::VARS->{$name} = $ret;
    }
    return $ret;
}

sub val {
    my ($self, $triple, $premise, $row) = @_;
    my $ret = $row->get($self->varIndex);
    if (defined $ret) {
	# Variable already bound in the row's result set.
	return $ret;
    }
    if (defined $premise) {
	# Extract variable's value from the premise.
	for (my $i = 0; $i < $premise->arity; $i++) {
	    my $pos = $premise->getSlot($i);
	    if ($pos->isa('W3C::Rdf::AlgaeCompileTree::Var') && 
		$pos->{VARNAME} eq $self->{VARNAME}) {
		return $triple->getPosition($i);
	    }
	}
	return undef;
    }
    # No way to resolve variable.
    if ($main::warnUnknownVariables || $main::dieUnknownVariables) {
	my $ex = new W3C::Rdf::UnmentionedVariableException(-var => $self->{VARNAME});
	if ($main::dieUnknownVariables) {
	    &throw($ex);
	}
	warn $ex->getMessage()."\n";
    }
    return undef;
}
sub assign {
    my ($self, $triple, $premise, $row, $value) = @_;
    $self->absorb($value, $row);
    return $value;
}

sub existential {0}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return '?'.$self->{VARNAME};
}

package W3C::Rdf::AlgaeCompileTree::NovelVar;
use W3C::Util::Exception;
sub new {
    my ($proto, $label, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $gensym = [];
    $label ||= "<gensym:$gensym>";
    my $self = $class->SUPER::new($label, 1, @exprParms);
    $self->{GENSYM} = $gensym; # keep name from being re-used.
    return $self;
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return $self->{VARNAME};
}

package W3C::Rdf::AlgaeCompileTree::NovelBNode;
use W3C::Util::Exception;
sub lookfor ($$) {
    my ($self, $row, $atoms) = @_;
    my $rowBinding = $row->get($self->varIndex);
    if (!$rowBinding) {
	$rowBinding = $self->{ALGAE2}{-atomDictionary}->createBNode($self->{ALGAE2}->getSourceAttribution);
	# Need to absorb the newly created value.
	if ($row) {
	    $row->set($self->varIndex, $rowBinding);
	} else {
	    # May not be used in static asserts ($row is null) .
	    &throw(new W3C::Util::Exception(-message => "functional bnode used in non-functional context."));
	}
    }
    return \ $self->varIndex;
    return $row->get($self->varIndex);
}

package W3C::Rdf::AlgaeCompileTree::KeyName;
use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($ATTRIB_GroundFact);

sub new {
    my ($proto, $name, $create, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{VARNAME} = $name;
    return $self;
}
sub getName {$_[0]->{VARNAME}}
sub val {
    my ($self, $triple, $premise, $row) = @_;
    return &getTripleAttribute($self->{VARNAME}, $triple);
}
sub assign {
    my ($self, $triple, $premise, $row, $value) = @_;
    return &setTripleAttribute($self->{VARNAME}, $triple, $value, $self->{ALGAE2}{-atomDictionary});
}
sub toString {$_[0]->{VARNAME}}

# Access to special variables
sub getTripleAttribute { # static
    my ($varname, $triple, $value, $atoms) = @_;
    if ($varname eq 'ENCODING') {
	my $o = $triple->getObject;
	if ($o->isa('W3C::Rdf::String')) {
	    return $o->getEncoding() || $atoms->getString('', 'PLAIN');
	} else {
	    &throw(new W3C::Util::SafeEvaluationException(-message => "ENCODNG only defined for literals"));
	}
    } elsif ($varname eq 'DATATYPE') {
	my $o = $triple->getObject;
	if ($o->isa('W3C::Rdf::String')) {
	    return $o->getDatatype() || $atoms->getString('', 'PLAIN');
	} else {
	    &throw(new W3C::Util::SafeEvaluationException(-message => "DATATYPE only defined for literals"));
	}
    } elsif ($varname eq 'LANG') {
	my $o = $triple->getObject;
	if ($o->isa('W3C::Rdf::String')) {
	    return $o->getLang() || $atoms->getString('', 'PLAIN');
	} else {
	    &throw(new W3C::Util::SafeEvaluationException(-message => "LANG only defined for literals"));
	}
    } elsif ($varname eq 'ATTRIB') {
	return $triple->getAttributionList->getFirstUri; # @@@
    } else {
	&throw(new W3C::Util::Exception(-message =>"unknown key word \"$varname\""));
    }
}
sub setTripleAttribute { # static
    my ($varname, $triple, $value, $atomDictionary) = @_;
    if ($varname eq 'ENCODING') {
	$triple->getObject->setEncoding($value);
    } elsif ($varname eq 'DATATYPE') {
	$triple->getObject->setDatatype($value);
    } elsif ($varname eq 'LANG') {
	$triple->getObject->setLang($value);
    } elsif ($varname eq 'ATTRIB') {
	my $auth = undef; # !!!
	$triple->getAttributionList->
	    setDirectAttribution($atomDictionary->
				 getGroundFactAttribution($value, undef, 
							  $auth, undef));
    } else {
	&throw(new W3C::Util::Exception(-message =>"unknown key word \"$varname\""));
    }
    return $value;
}

# ------- CONNECTIVES -------
package W3C::Rdf::AlgaeCompileTree::Constraint;
use W3C::Util::Exception;
sub new {
    my ($proto, $expr, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{EXPR} = $expr;
    return $self;
}

sub evaluateQTermAndConstraints {
    my ($self, $resultSet, $db, $modifier) = @_;
    for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	my $row = $e->nextElement;
	my $passed = 1;
	eval {
	    my $res = $self->val(undef, undef, $row);
	    if (!$self->{ALGAE2}->getEBV($res)) {
		$passed = 0;
	    }
	}; if ($@) {if (my $ex = &catch('W3C::Util::SafeEvaluationException')) {
	    $passed = 0;
#	} elsif (my $ex = &catch('W3C::Rdf::IncorrectTypeException')) {
#	    $row->addCaveat($ex);
#	    $passed = 0;
	} elsif (my $ex = &catch('W3C::Rdf::UnknownTypeException')) {
#	    $row->addCaveat($ex);
	    $passed = 0;
	} else {
#	    $row->addCaveat($ex);
	    &throw();
	}}

	if (!$passed) {
	    $row->eliminate;
	}
    }
}
sub val {
    my ($self, $triple, $premise, $row) = @_;
    return $self->{EXPR}->val($triple, $premise, $row);
}
sub nullOut {}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    return $self->{EXPR}->toString(%flags);
}

sub toSQL {
    my ($self, $algae, $term, $cWheres, $outer) = @_;
    if ($self->{EXPR}) {
	$self->{EXPR}->toSQL($algae, $term, $cWheres, $outer);
    }
}

package W3C::Rdf::AlgaeCompileTree::Binary;
sub new {
    my ($proto, $L, $R, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{L} = $L;
    $self->{R} = $R;
    return $self;
}

sub val {
    my ($self, $triple, $premise, $row) = @_;
    &throw(new W3C::Util::NotImplementedException(-object => $self));
}

sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $opStr = $self->opStr();
    if ($flags{-precTable} && exists $flags{-precTable}{$opStr} && 0) {
	my ($prec, $assoc) = @{$flags{-precTable}{$opStr}};
	my $lStr = $self->{L}->toString(%flags, -parentPrec => $prec);
	my $rStr = $self->{R}->toString(%flags, -parentPrec => $prec);
	if ($prec <= $flags{-parentPrec}) {
	    return "$lStr $opStr $rStr";
	} else {
	    return "($lStr $opStr $rStr)";
	}
    } else {
	my $lStr = $self->{L}->toString();
	my $rStr = $self->{R}->toString();
	return "($lStr $opStr $rStr)";
    }
}

package W3C::Rdf::AlgaeCompileTree::Expr;
use W3C::Util::Exception;
use vars qw($XSD_INT $XSD_FLOAT $STR $NUM $URI $BNODE $TYPE_MAP);
($XSD_INT, $XSD_FLOAT) = ('http://www.w3.org/2001/XMLSchema#integer', 'http://www.w3.org/2001/XMLSchema#float');
($STR, $NUM, $BNODE, $URI) = (1..4);
$TYPE_MAP = {};
sub addSelect {
    my ($self) = @_;
    my $name = $self->toString();
    $self->{ALGAE2}->addLabel($name, $self);
}
sub internedInt {
    my ($self, $value) = @_;
    # $value = 0 if ($value eq ''); # By default, perl returns '' for (1 == 2) # !!!
    my $dt = $self->{ALGAE2}{-atomDictionary}->getUri($XSD_INT);
    return $self->{ALGAE2}{-atomDictionary}->getString("$value", $dt, 'PLAIN');
}
sub toNum {
    my ($self, $node) = @_;
    if ($node->isa('W3C::Rdf::String')) {
	if (my $dt = $node->getDatatype) {
	    if ($dt->getUri eq $XSD_INT || 
		$dt->getUri eq $XSD_FLOAT) {
		return $node->getString();
	    }
	}
    }
    my $nodeStr = $node->toString();
    &throw(new W3C::Util::Exception(-message => "unable to convert $nodeStr to a NUM"));
}
sub guessType {
    my ($self, $node) = @_;
    if ($node->isa('W3C::Rdf::String')) {
	if (my $dt = $node->getDatatype) {
	    if ($dt->getUri eq $XSD_INT || 
		$dt->getUri eq $XSD_FLOAT) {
		return $NUM;
	    } else {
		return $STR;
	    }
	} elsif ($node->getString =~ m/^\d+(?:\.\d*)?/ || 
		 $node->getString =~ m/^\.\d+/) {
	    return $NUM;
	} else {
	    return $STR;
	}
    } elsif ($node->isa('W3C::Rdf::Uri')) {
	return $URI
    } elsif ($node->isa('W3C::Rdf::BNode')) {
	return $BNODE;
    } else {
	&throw(new W3C::Util::ProgramFlowException());
    }
}
sub cmp {
    my ($self, $l, $r) = @_;
    my ($lt, $rt) = ($self->guessType($l), $self->guessType($r));
    # sort order same as assignments for consts above.
    if ($lt != $rt) {
	return $lt <=> $rt;
    }
    if ($lt == $STR) {
	return $l->getString cmp $r->getString;
    }
    if ($lt == $NUM) {
	return $l->getString <=> $r->getString;
    }
    if ($lt == $BNODE) {
	return $l->getId <=> $r->getId;
    }
    if ($lt == $URI) {
	return $l->getUri cmp $r->getUri;
    }
    &throw(new W3C::Util::ProgramFlowException());
}

package W3C::Rdf::AlgaeCompileTree::Glob;
sub opStr {'@'}
sub val {
    my ($self, $triple, $premise, $row) = @_;
    my $l = $self->{L}->val($triple, $premise, $row);
    my $regex = $self->{R}->val($triple, $premise, $row)->getString;

    my $uriWildcard = '*';
    $regex = $self->mapWildcards($regex, $uriWildcard, '\\', '.*', ['~','!','@','#',"\$",'%','^','&','*','(',')','+','`','-','=',
								    '{','}','[',']','|',':','"',';','\'','<','>','?',',','.','/']);
#    $regex =~ s/\\/\\\\/g;
#    $regex =~ s/\//\\\//g;
#    $regex =~ s/\?/\./g;
#    $regex =~ s/\*/\.\*\?/g;
    my $cmp;
    if ($l->isa('W3C::Rdf::BNode')) {
	$cmp = '['.$l->getAttribution->getUri->getUri.':'.$l->getId.']';
    } elsif ($l->isa('W3C::Rdf::String')) {
	$cmp = $l->getString;
    } elsif ($l->isa('W3C::Rdf::Uri')) {
	$cmp = $l->getUri;
    } elsif ($l->isa('W3C::Rdf::Attribution')) {
	$cmp = $l->getUri->getUri;
    } else {
	&throw(new W3C::Util::Exception(-message => "don't know how to get string value for ".ref $l));
    }
    $self->internedInt($cmp =~ m/^$regex$/);
}

sub mapWildcards {
    my ($self, $uri, $uriWildcard, $escape, $dbWildcard, $dbSpecials) = @_;

    if ($uriWildcard eq $escape) {
	$uri =~ s/\Q$escape\E/$dbWildcard/g;
    } else {
	$uri =~ s/\Q$escape\E/$escape$escape/g;
    }

    foreach my $hideMe (@$dbSpecials) {
	if ($uriWildcard ne $hideMe) {
	    $uri =~ s/\Q$hideMe\E/$escape$hideMe/g;
	}
    }

    if ($uriWildcard ne $dbWildcard && $uriWildcard ne $escape) {
	if (length($dbWildcard) == 1) {
	    $uri =~ s/\Q$dbWildcard\E/$escape$dbWildcard/g;
	}
	$uri =~ s/\Q$uriWildcard\E/$dbWildcard/g;
    }

    return $uri;
}

package W3C::Rdf::AlgaeCompileTree::Or;
use W3C::Util::Exception;
sub opStr {'||';}

sub val {
    my ($self, $triple, $premise, $row) = @_;
    my $ret = undef;
    eval {
	$ret = $self->{L}->val($triple, $premise, $row);
    }; if ($@) {if (my $ex = &catch('W3C::Util::SafeEvaluationException')) {
    } else {
	&throw($ex);
    }}

    return $ret && $self->{ALGAE2}->getEBV($ret) ? $ret : $self->{R}->val($triple, $premise, $row);
}
sub toSQL {
    my ($self, $algae, $term, $cWheres, $outer) = @_;
    my ($l, $r) = ([], []);
    $self->{L}->toSQL($algae, $term, $l, $outer);
    $self->{R}->toSQL($algae, $term, $r, $outer);
    push (@$cWheres, $algae->_addWhereDisjunction($l, $r, $outer));
}

package W3C::Rdf::AlgaeCompileTree::And;
sub opStr {'&&';}
sub val {
    my ($self, $triple, $premise, $row) = @_;
    my $ret = $self->{L}->val($triple, $premise, $row);
    if (!$ret || ($ret->isa('W3C::Rdf::String') && !$ret->getString)) {
	return $ret;
    } else {
	return $self->{R}->val($triple, $premise, $row);
    }
}
sub toSQL {
    my ($self, $algae, $term, $cWheres, $outer) = @_;
    $self->{L}->toSQL($algae, $term, $cWheres, $outer);
    $self->{R}->toSQL($algae, $term, $cWheres, $outer);
}

package W3C::Rdf::AlgaeCompileTree::BinaryTest;
# Provide =, !=		on	r:term, xs:string, numeric, xs:dateTime
#         <, >, <=, >=	on	                   numeric, xs:dateTime
# -> http://unagi/2001/sw/DataAccess/rq23/#OperatorMapping Operator Mapping table
# =, !=		on	xs:string, numeric, r:term, xs:dateTime
# The rest are handled by W3C::Rdf::String::numericOrDTCompare .
use W3C::Util::Exception;
sub val {
    my ($self, $triple, $premise, $row) = @_;
    my $l = $self->{L}->val($triple, $premise, $row);
    my $r = $self->{R}->val($triple, $premise, $row);
    return $self->_val1($l, $r, $row);
}
sub _val1 { # < > <= >=
    my ($self, $l, $r, $row) = @_;
    if (UNIVERSAL::isa($l, 'W3C::Rdf::String') && UNIVERSAL::isa($r, 'W3C::Rdf::String')) {
	my $ret;
	if (!$l->getLang && !$l->getDatatype && 
	    !$r->getLang && !$r->getDatatype) {
	    # handle simple literal ops ala
	    # [[simple literal < simple literal => op:numeric-equal(fn:compare(A, B), -1)]]
	    $ret = $l->getString cmp $r->getString;
	} elsif ($self->{ALGAE2}{-logicExtensions}{'http://jena.hpl.hp.com/2005/05/test-manifest-extra#LeGeIncludeEq'}) {
	    my $ret1;
	    eval {
		$ret1 = $self->{ALGAE2}->compare($l, $r);
	    }; if ($@) {if (my $ex = &catch('W3C::Util::SafeEvaluationException')) {
		return &W3C::Rdf::AlgaeCompileTree::EquivTest::_val1($self, $l, $r, $row);
	    }}
	    return $ret1;
	} else {
	    $ret = $self->{ALGAE2}->compare($l, $r);
	}
	return $self->internedInt($self->binaryTest($ret));
    } else {
	&throw(new W3C::Rdf::IncorrectTypeException(-type => UNIVERSAL::isa($l, 'W3C::Rdf::String') ? ref $r : ref $l, -function => '_val1'));
    }
}
sub toSQL {
    my ($self, $algae, $term, $cWheres, $outer) = @_;
    my $l = $self->{L};
    my $r = $self->{R};
    if ($l->isa('W3C::Rdf::AlgaeCompileTree::Var')) {
	if ($r->isa('W3C::Rdf::AlgaeCompileTree::Num')) {
	    my ($firstAlias, $firstField) = $algae->_getFieldForVariable($term, $l);
	    push (@$cWheres, $algae->_addWhereConst($firstAlias, $firstField, $self->opSQLstr(), $r->symbol, $term, $outer));
	} elsif ($r->isa('W3C::Rdf::AlgaeCompileTree::Url')) {
	    my ($firstAlias, $firstField) = $algae->_getFieldForVariable($term, $l);
	    push (@$cWheres, $algae->_addWhereConst($firstAlias, $firstField, $self->opSQLstr(), $r->getUrl, $term, $outer));
	} else {
	    &throw(new W3C::Util::Exception(-message => "what is a $r?"));
	}
    }
}

package W3C::Rdf::AlgaeCompileTree::EquivTest;
use W3C::Util::Exception;
# Provide =, != on everything that can be compared for = but not for < or >.
# So far, just r:term, xs:string.
# l and r will be the same atom if they are the same term or same string.
# Relay to SUPER for everything else.
sub _val1 {
    my ($self, $l, $r, $row) = @_;
    my $ret;
    eval {
	if ($l == $r) {
	    $ret = 0;
	} elsif (UNIVERSAL::isa($l, 'W3C::Rdf::String') && UNIVERSAL::isa($r, 'W3C::Rdf::String')) {
	    # They are comparable as literals.
	    my $lLang = $l->getLang;
	    my $rLang = $r->getLang;
	    if ($self->{ALGAE2}{-logicExtensions}{'http://jena.hpl.hp.com/2005/05/test-manifest-extra#LangCaseInsensitivity'} &&
		!$l->getDatatype && !$r->getDatatype && "\U$lLang" eq "\U$rLang") {
		$ret = $l->getString cmp $r->getString;
	    } else {
		$ret = $self->{ALGAE2}->compare($l, $r);
	    }
	} else {
	    $ret = 1;
	}
	$ret = $self->internedInt($self->binaryTest($ret));
    }; if ($@) {if (my $ex = &catch('W3C::Util::SafeEvaluationException')) {
	if ($self->{ALGAE2}{-logicExtensions}{'http://jena.hpl.hp.com/2005/05/test-manifest-extra#KnownTypesDefault2Neq'}
	    && ((($r->getDatatype && $l->getLang) || ($l->getDatatype && $r->getLang))
		||
		((!$r->getDatatype || $self->{ALGAE2}->getNumericBaseType($r))
		 && 
		 (!$l->getDatatype || $self->{ALGAE2}->getNumericBaseType($l))))) { # !!! non-mon
	    # printf("%49s ?= %-49s => %s\n", $l->toString, $r->toString, ref $ex);
	    $ret = $self->internedInt($self->binaryTest(1));
	} else {
	    &throw($ex);
	}
    } else {
	die $@;
    }}
    return $ret;
}
sub opSQLstr {return $_[0]->opStr();} # SQL operators are the same as algae operators except for the Eq.

package W3C::Rdf::AlgaeCompileTree::Eq;
sub opStr {'=='}
sub opSQLstr {'='}
sub binaryTest {
    my ($self, $val) = @_;
    return $val == 0 ? 1 : 0;
}

package W3C::Rdf::AlgaeCompileTree::Ne;
sub opStr {'!='}
sub binaryTest {
    my ($self, $val) = @_;
    return $val != 0 ? 1 : 0;
}

package W3C::Rdf::AlgaeCompileTree::Lt;
sub opStr {'<';}
sub binaryTest {
    my ($self, $val) = @_;
    return $val < 0 ? 1 : 0;
}

package W3C::Rdf::AlgaeCompileTree::Le;
sub opStr {'<=';}
sub binaryTest {
    my ($self, $val) = @_;
    return $val < 1 ? 1 : 0;
}

package W3C::Rdf::AlgaeCompileTree::Gt;
sub opStr {'>';}
sub binaryTest {
    my ($self, $val) = @_;
    return $val > 0 ? 1 : 0;
}

package W3C::Rdf::AlgaeCompileTree::Ge;
sub opStr {'>=';}
sub binaryTest {
    my ($self, $val) = @_;
    return $val > -1 ? 1 : 0;
}

package W3C::Rdf::AlgaeCompileTree::BinaryArith;
sub val {
    my ($self, $triple, $premise, $row) = @_;
    my $l = $self->{L}->val($triple, $premise, $row);
    my $r = $self->{R}->val($triple, $premise, $row);
    return $self->{ALGAE2}->binaryArith($self->opStr, $l, $r);
    my $ret = undef;
    eval {
	my ($lDt, $lVal) = $l->numericVal(); # may throw SafeEvaluationException on alien types
	my ($rDt, $rVal) = $r->numericVal();
	my $val = $self->binaryArith($lVal, $rVal);
	my $dt = $self->{ALGAE2}{-atomDictionary}->promoteNumericDatatype($lDt, $rDt); # !!! find upper-most common type
	$ret = $self->{ALGAE2}{-atomDictionary}->getString($val, $dt, 'PLAIN', undef);
    }; if ($@) {if (my $ex = &catch('W3C::Util::SafeEvaluationException')) {
	my $opStr = $self->opStr();
	$ex->{-message} = "$opStr only works on numerics.";
	$self->checkAlienTypeAndFail($ex->{-message});
	&throw($ex);
    } else {
	&throw();
    }}
    return $ret;
}

package W3C::Rdf::AlgaeCompileTree::Plus;
sub opStr {'+';}
sub binaryArith {
    my ($self, $lVal, $rVal) = @_;
    return $lVal + $rVal;
}

package W3C::Rdf::AlgaeCompileTree::Minus;
sub opStr {'-';}
sub binaryArith {
    my ($self, $lVal, $rVal) = @_;
    return $lVal - $rVal;
}

package W3C::Rdf::AlgaeCompileTree::Multiply;
sub opStr {'*';}
sub binaryArith {
    my ($self, $lVal, $rVal) = @_;
    return $lVal * $rVal;
}

package W3C::Rdf::AlgaeCompileTree::Exp;
sub opStr {'^';}
sub binaryArith {
    my ($self, $lVal, $rVal) = @_;
    return $lVal ** $rVal;
}

package W3C::Rdf::AlgaeCompileTree::Divide;
sub opStr {'/';}
sub binaryArith {
    my ($self, $lVal, $rVal) = @_;
    return $lVal / $rVal;
}

package W3C::Rdf::AlgaeCompileTree::Modulo;
sub opStr {'%';}
sub binaryArith {
    my ($self, $lVal, $rVal) = @_;
    return $lVal % $rVal;
}

package W3C::Rdf::AlgaeCompileTree::Xor;
sub opStr {'^';}
sub binaryArith {
    my ($self, $lVal, $rVal) = @_;
    return $lVal ^ $rVal;
}

package W3C::Rdf::AlgaeCompileTree::Assign;
sub opStr {'='}
sub val {
    my ($self, $triple, $premise, $row) = @_;
    return $self->{L}->assign($triple, $premise, $row, $self->{R}->val($triple, $premise, $row));
}
sub getAssoc {$CalcTree::RIGHT;}

package W3C::Rdf::AlgaeCompileTree::Unary;
use W3C::Util::Exception;

sub new {
    my ($proto, $M, @exprParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@exprParms);
    $self->{M} = $M;
    return $self;
}

sub val {
    my ($self, $triple, $premise, $row) = @_;
    &throw(new W3C::Util::NotImplementedException(-object => $self));
}

sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
#    my $val = $self->val();
    my $opStr = $self->opStr();
    if ($flags{-precTable} && exists $flags{-precTable}{$opStr}) {
	my ($outPrec, $outAssoc) = @{$flags{-precTable}{$opStr}};
	my $mStr = $self->{M}->toString(%flags, -parentPrec => $outPrec);
	if ($outPrec < $flags{-parentPrec} || 
	    ($outPrec == $flags{-parentPrec} && $self->getAssoc == $outAssoc)) {
	    return "$opStr $mStr"; # = $val)";
	} else {
	    return "($opStr $mStr)"; # = $val)";
	}
    } else {
	my $mStr = $self->{M}->toString();
	return "($opStr $mStr)"; # = $val)";
    }
}

sub W3C::Rdf::AlgaeCompileTree::Neg::opStr {'NEG';}
sub W3C::Rdf::AlgaeCompileTree::Neg::val {
    my ($self, $triple, $premise, $row) = @_;
    $self->internedInt(-$self->{ALGAE2}->getNumericBaseType($self->{M}->val($triple, $premise, $row)));
}
sub W3C::Rdf::AlgaeCompileTree::Neg::getAssoc {$CalcTree::RIGHT;}

sub W3C::Rdf::AlgaeCompileTree::Not::opStr {'NOT';}
sub W3C::Rdf::AlgaeCompileTree::Not::val {
    my ($self, $triple, $premise, $row) = @_;
    $self->internedInt(!$self->{ALGAE2}->getEBV($self->{M}->val($triple, $premise, $row)));
}
sub W3C::Rdf::AlgaeCompileTree::Not::getAssoc {$CalcTree::RIGHT;}

sub W3C::Rdf::AlgaeCompileTree::BitFlip::opStr {'~';}
sub W3C::Rdf::AlgaeCompileTree::BitFlip::val {
    my ($self, $triple, $premise, $row) = @_;
    $self->internedInt(~ $self->{M}->val($triple, $premise, $row));} # !!!
sub W3C::Rdf::AlgaeCompileTree::BitFlip::getAssoc {$CalcTree::RIGHT;}

sub W3C::Rdf::AlgaeCompileTree::Lang::opStr {'!!!';}
sub W3C::Rdf::AlgaeCompileTree::Lang::val {
    my ($self, $triple, $premise, $row) = @_;
    $self->{M}->getLang();}

sub W3C::Rdf::AlgaeCompileTree::Label::opStr {'!!!';}
sub W3C::Rdf::AlgaeCompileTree::Label::val {
    my ($self, $triple, $premise, $row) = @_;
    my $val = $self->{M}->val($triple, $premise, $row);
    if ($val->isa('W3C::Rdf::String')) {
	return $val;
    } else {
	&throw(new W3C::Rdf::FailureOnTypeException(-expect => 'W3C::Rdf::String', 
						    -got => ref $val));
    }
}

sub resourceFunc {
    my ($funcName, $args, $atoms) = @_;
    if (@$args != 1) {
	&throw(new W3C::Util::Exception(-message => "invocation: resource(expression)"));
    }
    my $arg = $args->[0];
    if (UNIVERSAL::isa($arg, 'W3C::Rdf::String')) {
	my $dt = $arg->getDatatype();
	if (!$dt || 
	    $dt->getUri() eq 'http://www.w3.org/2001/XMLSchema#string') {
	    return $atoms->getUri($arg->getString(), undef); # !!! pick up base from parser?
	}
    } elsif (UNIVERSAL::isa($arg, 'W3C::Rdf::Uri')) {
	return $arg;
    }
    &throw(new W3C::Util::SafeEvaluationException(-message => "rdfs:Resource only works on literals and URIs"));
};

sub strFunc {
    my ($funcName, $args, $atoms) = @_;
    if (@$args != 1) {
	&throw(new W3C::Util::Exception(-message => "invocation: str(expression)"));
    }
    my $arg = $args->[0];
    my $dt = $funcName eq 'http://www.w3.org/2000/01/rdf-schema#Literal' ? 
	undef : 
	$atoms->getUri('http://www.w3.org/2001/XMLSchema#string', undef);
    if (UNIVERSAL::isa($arg, 'W3C::Rdf::String')) {
	# strip off lang and datatype
	return $atoms->getString($arg->getString(), $dt, 'PLAIN', undef);
    }
    if (UNIVERSAL::isa($arg, 'W3C::Rdf::Uri')) {
	return $atoms->getString($arg->getUri(), $dt, 'PLAIN', undef);
    }
    &throw(new W3C::Util::SafeEvaluationException(-message => "str only works on literals and URIs"));
};

sub booleanFunc {
    my ($funcName, $args, $atoms) = @_;
    if (@$args != 1) {
	&throw(new W3C::Util::Exception(-message => "invocation: $funcName(expression)"));
    }
    my $arg = $args->[0];
    if (UNIVERSAL::isa($arg, 'W3C::Rdf::String')) {
	my $val = $arg->getString();
	my $dt = $arg->getDatatype();
	if ($dt) {
	    $dt = $dt->getUri();
	}
	if ($dt eq 'http://www.w3.org/2001/XMLSchema#boolean') {
	    return $arg;
	}
	if ($dt eq 'http://www.w3.org/2001/XMLSchema#string' || !defined $dt) {
	    if ($val =~ m/^(0|1|false|true)$/i) {
		return $atoms->getString($val, $atoms->getUri('http://www.w3.org/2001/XMLSchema#boolean', undef, undef), 'PLAIN');
	    }
	    &throw(new W3C::Util::SafeEvaluationException(-message => "valid boolean forms: 1, 0, true, false"));
	}
	if ($dt eq 'http://www.w3.org/2001/XMLSchema#float' || 
	    $dt eq 'http://www.w3.org/2001/XMLSchema#double' || 
	    $dt eq 'http://www.w3.org/2001/XMLSchema#decimal' || 
	    $dt eq 'http://www.w3.org/2001/XMLSchema#integer') {
	    $val = $val ? 'true' : 'false';
	    return $atoms->getString($val, $atoms->getUri('http://www.w3.org/2001/XMLSchema#boolean', undef, undef), 'PLAIN');
	}
    }
    &throw(new W3C::Util::SafeEvaluationException(-message => "$funcName only works on literals"));
};

my %decPatterns = ('http://www.w3.org/2001/XMLSchema#float' => '[\-+]?(((\\d+(\\.\\d*)?)|(\\.\\d+)))([eE][\-+]?\\d+)?', 
		   'http://www.w3.org/2001/XMLSchema#integer' => '[\-+]?\\d+', 
		   'http://www.w3.org/2001/XMLSchema#decimal' => '[\-+]?(((\\d+(\\.\\d*)?)|(\\.\\d+)))', 
		   'http://www.w3.org/2001/XMLSchema#double' => '[\-+]?(((\\d+(\\.\\d*)?)|(\\.\\d+)))([eE][\-+]?\\d+)?', 
		   'http://www.w3.org/2001/XMLSchema#nonPositiveInteger' => '(\-\\d+)|0', 
		   'http://www.w3.org/2001/XMLSchema#negativeInteger' => '\-\\d+', 
		   'http://www.w3.org/2001/XMLSchema#long' => '[\-+]?\\d+', 
		   'http://www.w3.org/2001/XMLSchema#int' => '[\-+]?\\d+', 
		   'http://www.w3.org/2001/XMLSchema#short' => '[\-+]?\\d+', 
		   'http://www.w3.org/2001/XMLSchema#byte' => '[\-+]?\\d+', 
		   'http://www.w3.org/2001/XMLSchema#nonNegativeInteger' => '\\d+', 
		   'http://www.w3.org/2001/XMLSchema#unsignedLong' => '\\d+', 
		   'http://www.w3.org/2001/XMLSchema#unsignedInt' => '\\d+', 
		   'http://www.w3.org/2001/XMLSchema#unsignedShort' => '\\d+', 
		   'http://www.w3.org/2001/XMLSchema#unsignedByte' => '\\d+', 
		   'http://www.w3.org/2001/XMLSchema#positiveInteger' => '\\d+', 
    );

sub decFunc {
    my ($funcName, $args, $atoms) = @_;
    if (@$args != 1) {
	&throw(new W3C::Util::Exception(-message => "invocation: $funcName(expression)"));
    }
    my $arg = $args->[0];
    if (UNIVERSAL::isa($arg, 'W3C::Rdf::String')) {
	my $val = $arg->getString();
	my $dt = $arg->getDatatype();
	if ($dt) {
	    $dt = $dt->getUri();
	}
	if ($dt eq 'http://www.w3.org/2001/XMLSchema#integer') {
	    return $arg;
	}
	if (($dt eq 'http://www.w3.org/2001/XMLSchema#float' || 
	     $dt eq 'http://www.w3.org/2001/XMLSchema#string' || 
	     $dt eq 'http://www.w3.org/2001/XMLSchema#double' || 
	     !defined $dt) && 
	    $val =~ m/^$decPatterns{$funcName}$/) {
	    return $atoms->getString($val, $atoms->getUri('http://www.w3.org/2001/XMLSchema#integer', undef, undef), 'PLAIN');
	}
	# strip off lang and datatype
    }
    &throw(new W3C::Util::SafeEvaluationException(-message => "$funcName only works on parsable literals"));
};

sub numericCast {
    my ($funcName, $args, $atoms) = @_;
    if (@$args != 1) {
	&throw(new W3C::Util::Exception(-message => "invocation: str(expression)"));
    }
    my $str = $args->[0];
    if (UNIVERSAL::isa($str, 'W3C::Rdf::String')) {
	my $val = $str->getString();
	my $dt = $str->getDatatype();
	if ($dt) {
	    $dt = $dt->getUri();
	    if ($decPatterns{$dt}) {
		return $atoms->getString($str->getString(), $atoms->getUri($funcName), $str->getEncoding(), $str->getLang());
	    }
	    if ($dt ne 'http://www.w3.org/2001/XMLSchema#string') {
		&throw(new W3C::Util::SafeEvaluationException(-message => "only numeric types and strings or literals with valid lexical forms may be cast to $funcName"));
	    }
	}
	if ($val =~ m/^$decPatterns{$funcName}$/) {
	    return $atoms->getString($val, $atoms->getUri($funcName), $str->getEncoding(), $str->getLang());
	}
	&throw(new W3C::Util::SafeEvaluationException(-message => "invalid lexical form: \"$val\" cannot be cast to $funcName"));
    }
    &throw(new W3C::Util::SafeEvaluationException(-message => "$funcName only works on literals"));
}

sub dateTimeFunc {
    my ($funcName, $args, $atoms) = @_;
    if (@$args != 1) {
	&throw(new W3C::Util::Exception(-message => "invocation: $funcName(expression)"));
    }
    my $arg = $args->[0];
    if (UNIVERSAL::isa($arg, 'W3C::Rdf::String')) {
	my $val = $arg->getString();
	my $dt = $arg->getDatatype();
	if ($dt) {
	    $dt = $dt->getUri();
	}
	if ($dt eq 'http://www.w3.org/2001/XMLSchema#dateTime') {
	    return $arg;
	}
	if ($dt eq 'http://www.w3.org/2001/XMLSchema#string' || !defined $dt) {
	    my $ret;
	    eval {
		&W3C::Rdf::Algae2::DateTime_to_CTime($val);
		$ret = $atoms->getString($val, $atoms->getUri('http://www.w3.org/2001/XMLSchema#dateTime', undef, undef), 'PLAIN');
	    }; if ($@) {if (my $ex = &catch('W3C::Util::Exception')) {
		&throw($ex);
	    } else {
		&throw(new W3C::Util::Exception(-message => "got exception \"$@\" in DateTime_to_CTime."));
	    }}
	    return $ret;
	}
    }
    &throw(new W3C::Util::SafeEvaluationException(-message => "$funcName only works on literals and xsd:strings"));
};

my %Functions = ('http://www.w3.org/2000/01/rdf-schema#Resource' => \&resourceFunc, 
		 'http://www.w3.org/2000/01/rdf-schema#Literal' => \&strFunc, 
		 'http://www.w3.org/2001/XMLSchema#string' => \&strFunc, 
		 'http://www.w3.org/2001/XMLSchema#boolean' => \&booleanFunc, 
		 'http://www.w3.org/2001/XMLSchema#float' => \&decFunc, 
		 'http://www.w3.org/2001/XMLSchema#integer' => \&decFunc, 
		 'http://www.w3.org/2001/XMLSchema#decimal' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#double' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#float' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#decimal' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#integer' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#nonPositiveInteger' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#negativeInteger' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#long' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#int' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#short' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#byte' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#nonNegativeInteger' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#unsignedLong' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#unsignedInt' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#unsignedShort' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#unsignedByte' => \&numericCast, 
		 'http://www.w3.org/2001/XMLSchema#positiveInteger' => \&numericCast, 

		 'http://www.w3.org/2001/XMLSchema#dateTime' => \&dateTimeFunc);
use W3C::Rdf::Atoms qw($Value_NULL);
my %Operations = ('str' => sub {
		      my ($funcName, $args, $atoms) = @_;
		      return &strFunc('http://www.w3.org/2000/01/rdf-schema#Literal', $args, $atoms);
		  }, 
		  'lang' => sub {
		      my ($funcName, $args, $atoms) = @_;
		      if (@$args != 1) {
			  &throw(new W3C::Util::Exception(-message => "invocation: str(expression)"));
		      }
		      if (UNIVERSAL::isa($args->[0], 'W3C::Rdf::String')) {
			  my $ret = $args->[0]->getLang() || '';
			  return $atoms->getString($ret, undef, 'PLAIN');
		      }
		      &throw(new W3C::Util::SafeEvaluationException(-message => "lang only works on literals"));
		  }, 
		  'datatype' => sub {
		      my ($funcName, $args, $atoms) = @_;
		      if (@$args != 1) {
			  &throw(new W3C::Util::Exception(-message => "invocation: str(expression)"));
		      }
		      if (UNIVERSAL::isa($args->[0], 'W3C::Rdf::String') && !$args->[0]->getLang()) {
			  my $ret = $args->[0]->getDatatype();
			  return $ret ? $ret : $atoms->getUri('http://www.w3.org/2001/XMLSchema#string', undef);
		      }
		      &throw(new W3C::Util::SafeEvaluationException(-message => "datatype only works on literals"));
		  });
my %IntegerOperations = ('bound' => sub {
    my ($funcName, $args, $atoms) = @_;
    if (@$args != 1) {
	&throw(new W3C::Util::Exception(-message => "invocation: bound(expression)"));
    }
    return $args->[0] == $Value_NULL ? 0 : 1;
}, 
			 'isuri' => sub {
     my ($funcName, $args, $atoms) = @_;
     if (@$args != 1) {
	 &throw(new W3C::Util::Exception(-message => "invocation: isURI(expression)"));
     }
     return UNIVERSAL::isa($args->[0], 'W3C::Rdf::Uri') ? 1 : 0;
 }, 
			 'isiri' => sub {
     my ($funcName, $args, $atoms) = @_;
     if (@$args != 1) {
	 &throw(new W3C::Util::Exception(-message => "invocation: isIRI(expression)"));
     }
     return UNIVERSAL::isa($args->[0], 'W3C::Rdf::Uri') ? 1 : 0;
 }, 
			 'langmatches' => sub {
     my ($funcName, $args, $atoms) = @_;
     if (@$args != 2) {
	 &throw(new W3C::Util::Exception(-message => "invocation: langMatches(languageTag, pattern)"));
     }
     if (!UNIVERSAL::isa($args->[0], 'W3C::Rdf::String') || !UNIVERSAL::isa($args->[1], 'W3C::Rdf::String')) {
	 &throw(new W3C::Util::SafeEvaluationException(-message => "langMatches only defined for strings"));
     }
     my ($langTag, $langRange) = ($args->[0]->getString, $args->[1]->getString);
     return $langRange eq '*' ? $langTag eq '' ? 0 : 1 : 
	 $langTag =~ m/^$langRange(?:-|$)/i ? 1 : 0;
 }, 
			 'sameterm' => sub {
     my ($funcName, $args, $atoms) = @_;
     if (@$args != 2) {
	 &throw(new W3C::Util::Exception(-message => "invocation: sameTerm(expression)"));
     }
     return $args->[0] == $args->[1] ? 1 : 0;
 }, 
			 'isblank' => sub {
     my ($funcName, $args, $atoms) = @_;
     if (@$args != 1) {
	 &throw(new W3C::Util::Exception(-message => "invocation: isBlank(expression)"));
     }
     return UNIVERSAL::isa($args->[0], 'W3C::Rdf::BNode') ? 1 : 0;
 }, 
			 'isliteral' => sub {
     my ($funcName, $args, $atoms) = @_;
     if (@$args != 1) {
	 &throw(new W3C::Util::Exception(-message => "invocation: isLiteral(expression)"));
     }
     return UNIVERSAL::isa($args->[0], 'W3C::Rdf::String') ? 1 : 0;
 }, 
			 'sameas' => sub {
     my ($funcName, $args, $atoms) = @_;
     if (@$args != 2) {
	 &throw(new W3C::Util::Exception(-message => "invocation: sameAs(expression, expression)"));
     }
     return $args->[0] == $args->[1];
 }, 
			 'regex' => sub {
     my ($funcName, $args, $atoms) = @_;
     if (@$args != 2 && @$args != 3) {
	 &throw(new W3C::Util::Exception(-message => "invocation: regex(expression, regular-expression [, smix])"));
     }
     if (!UNIVERSAL::isa($args->[0], 'W3C::Rdf::String') || 
	 !UNIVERSAL::isa($args->[1], 'W3C::Rdf::String')) {
	 &throw(new W3C::Util::SafeEvaluationException(-message => "regex only works for literal patterns on literals"));
     }
     my $str = $args->[0]->getString();
     my $regex = $args->[1]->getString();
     my $flags = '';
     if (@$args == 3) {
	 if (!UNIVERSAL::isa($args->[2], 'W3C::Rdf::String')) {
	     &throw(new W3C::Util::SafeEvaluationException(-message => "invocation: regex(expression, regular-expression [, smix])"));
	 }
	 $flags = $args->[2]->getString();
	 if ($flags !~ m/^[smix]*$/) {
	     &throw(new W3C::Util::SafeEvaluationException(-message => "invocation: regex(expression, regular-expression [, smix])"));
	 }
     }
     $regex =~ s|\/|\\\/|g;
     return $str =~ m/(?$flags)$regex/;
 });
my %AtomOperations = ('hostname' => sub {
     my ($funcName, $args, $atoms) = @_;
     if (@$args != 1) {
	 &throw(new W3C::Util::Exception(-message => "hostname takes one argument"));
     }
     if (UNIVERSAL::isa($args->[0], 'W3C::Rdf::Uri')) {
	 require URI::URL;
	 my (undef, undef, undef, $hostname, @rest) = new URI::URL($args->[0]->getUri)->crack;
	 return $atoms->getString($hostname, undef, 'PLAIN');
     }
     &throw(new W3C::Util::SafeEvaluationException(-message => "hostname requires a uri argument"));
 });

package W3C::Rdf::AlgaeCompileTree::FuncCall;
use W3C::Util::Exception;
sub new {
    my ($proto, $funcName, $args, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{FUNC_NAME} = $funcName;
    $self->{ARGS} = $args;
    return $self;
}
sub val {
    my ($self, $triple, $premise, $row) = @_;

    my $args = [map {ref $_ ? $_->val($triple, $premise, $row) : $_} @{$self->{ARGS}}];
    # profiles supported as functions:
    if (ref $self->{FUNC_NAME} && UNIVERSAL::isa($self->{FUNC_NAME}, 'W3C::Rdf::AlgaeCompileTree::UrlBase')) {
	# Dispatch functions
	my $funcName = $self->{FUNC_NAME}->getUrl();
	if (my $fp = $Functions{$funcName}) {
	    return &$fp($funcName, $args, $self->{ALGAE2}{-atomDictionary});
	    $self->checkAlienTypeAndFail("$funcName only works on parsable literals");
	}
	if ($self->{ALGAE2}->getParserMode()) {
	    return undef;
	}
	&throw(new W3C::Rdf::UnknownFunctionException(-function => $funcName));
    }
    my $funcName = $self->{FUNC_NAME};
    # Dispatch operations:
    if (my $fp = $IntegerOperations{$funcName}) {
	return $self->internedInt(&$fp($funcName, $args, $self->{ALGAE2}{-atomDictionary}));
    }
    if (my $fp = $AtomOperations{$funcName}) {
	return &$fp($funcName, $args, $self->{ALGAE2}{-atomDictionary});
    }
    if (my $fp = $Operations{$funcName}) {
	return &$fp($funcName, $args, $self->{ALGAE2}{-atomDictionary});
    }
    my $selfStr = $self->toString();
    &throw(new W3C::Util::UnsafeEvaluationException(-message => "$selfStr not implemented"));
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $funcNameStr = ref $self->{FUNC_NAME} && UNIVERSAL::isa($self->{FUNC_NAME}, 'W3C::Rdf::AlgaeCompileTree::QName') ? 
	$self->{FUNC_NAME}->toString(%flags) : 
	"\U$self->{FUNC_NAME}";
    my $argsStr = join(' ', map {$_->toString(%flags)} @{$self->{ARGS}});
    return "$funcNameStr($argsStr)";
}

package W3C::Rdf::AlgaeCompileTree::Operator;
use W3C::Util::Exception;
use W3C::Rdf::Atoms qw($Value_NULL);
sub new {
    my ($proto, $funcName, $args, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    return $class->SUPER::new("\L$funcName", $args, @actionParms);
}

# profiles supported in the grammar:

# ProfileQuery
package W3C::Rdf::AlgaeCompileTree::ProfileQuery;
use W3C::Util::Exception;
sub new {
    my ($proto, $qClass, $variable, @actionParms) = @_;
    my $class = ref($proto) || $proto;
    my $self = $class->SUPER::new(@actionParms);
    $self->{CLASS} = $qClass;
    $self->{VARIABLE} = $variable;
    return $self;
}
sub delayedEvaluate {
    my $ns = 'http://lists.w3.org/Archives/Public/public-rdf-dawg/2004AprJun/0699.html#';
    my $PROFILE_core = 'http://www.w3.org/2004/05/06-Algae/#core';
    my $PROFILE_assert = 'http://www.w3.org/2004/06/20-rules/#assert';
    my $PROFILE_profQuery = "${ns}profileQuery";
    my $sStr = "${ns}ThisService";

    my ($self, $resultSet) = @_;
    my $pClass = "${ns}profileList";
    my $classStr = $self->{CLASS}->getUrl;
    if ($classStr eq $pClass) {
	for (my $e = $resultSet->elements; $e->hasMoreElements;) {
	    my $row = $e->nextElement;
	    foreach my $profile ($PROFILE_core, 
				 $PROFILE_assert, $PROFILE_profQuery) {
		my $newRow = $row->duplicate;
		my $s = $self->{ALGAE2}{-atomDictionary}->getUri($sStr);
		my $p = $self->{ALGAE2}{-atomDictionary}->getUri($PROFILE_profQuery);
		my $o = $self->{ALGAE2}{-atomDictionary}->getUri($profile);
		my $statement = $self->{ALGAE2}{-atomDictionary}->getStatement($p, $s, $o, undef, undef);
		$newRow->addProofs([$statement]);
		$self->{VARIABLE}->absorb($o, $newRow);
	    }
	    $row->eliminate;
	}
    } else {
	&throw(new W3C::Util::UnsafeEvaluationException(-message => 
		       "profileQuery class \"$classStr\" not supported"));
    }
}
sub toString {
    my ($self, %flags) = &main::_defaultPrec(@_);
    my $nodeStr = join (' ', map {$_->toString(%flags)} @{$self->{NODES}});
    return "profileQuery ($nodeStr)";
}

package W3C::Rdf::AlgaeCompileTree::FakeAlgae2;
sub new {
    my ($proto, $resultSet, %flags) = @_;
    my $class = ref($proto) || $proto;
    my $self = {ResultSet => $resultSet, %flags};
    bless ($self, $class);
    return $self;
}
sub getResultSet {
    my ($self) = @_;
    return $self->{ResultSet};
}
sub dumpStuff {
    my ($self, $type, $algae2, $decls) = @_;
    print "";
}
sub getSourceAttribution {
    my ($self) = @_;
    return $self->{-sourceAttribution};
}

package W3C::Rdf::AlgaeCompileTree::FakeParser;
sub new {
    my ($proto, $resultSet, %parms) = @_;
    my $class = ref($proto) || $proto;
    my $self = {ResultSet => $resultSet, %parms};
    $self->{ALGAE2} = new W3C::Rdf::AlgaeCompileTree::FakeAlgae2($resultSet, %parms);
    bless ($self, $class);
    return $self;
}
sub YYData {
    my ($self) = @_;
    return $self;
}
sub dumpStuff999 {
    my ($self, $type, $algae2, $decls) = @_;
    print "";
}

1;

__END__

=head1 NAME

W3C::Rdf::AlgaeCompileTree - RDF query objects

=head1 SYNOPSIS

  # in a parser...
  use W3C::Rdf::AlgaeCompileTree;
  my $t1 = new W3C::Rdf::AlgaeCompileTree::Decl([$p1, $s1, $o1], 
				$constraints1, $self);
  my $t2 = new W3C::Rdf::AlgaeCompileTree::Decl([$p2, $s2, $o2], 
				$constraints2, $self);
  my $conj = new W3C::Rdf::AlgaeCompileTree::Conjunction($t1, $t2, $self)

=head1 DESCRIPTION

Parsers generate AlgaeCompileTrees and hand them to the Algae2 object. Algae2
calls the compile tree to perforn queries/assertions/rules.

This module is part of the W3C::Rdf CPAN module.

=head1 METHODS

    $atomDictionary, $namespaceHandler, 
	$sources, $rdfApp, $sourceAttrib, $flags

=head2 immediateEvaluate($resultSet)

Perform compile-time evaluations.

no return value

=head2 delayedEvaluate($resultSet)

Perform post-compile-time (pass 2) evaluations. This is for query languages
that require a second pass to do things like resolve namespace prefixes that
are declared after a dependent qname is first used.

no return value

=head2 val($triple, $premise, $row)

Perform the query evaluation. I don't remember what the hell the $premise is,
but it sure looks important.

returns an interned RDF Atom

=head1 AUTHOR

Eric Prud'hommeaux <eric@w3.org>

=head1 SEE ALSO

W3C::Rdf::Algae2(1) W3C::Rdf::AlgaeParser(1) W3C::Rdf::Atom(1) perl(1).

=cut
