libdap  Updated for version 3.17.0
D4ConstraintEvaluator.cc
00001 // -*- mode: c++; c-basic-offset:4 -*-
00002 
00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00004 // Access Protocol.
00005 
00006 // Copyright (c) 2002,2003 OPeNDAP, Inc.
00007 // Author: James Gallagher <jgallagher@opendap.org>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022 //
00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00024 
00025 #include <string>
00026 #include <sstream>
00027 #include <iterator>
00028 
00029 //#define DODS_DEBUG
00030 
00031 #include "D4CEScanner.h"
00032 #include "D4ConstraintEvaluator.h"
00033 #include "d4_ce_parser.tab.hh"
00034 #include "DMR.h"
00035 #include "D4Group.h"
00036 #include "D4Dimensions.h"
00037 #include "BaseType.h"
00038 #include "Array.h"
00039 #include "Constructor.h"
00040 
00041 #include "parser.h"             // for get_ull()
00042 #include "debug.h"
00043 
00044 namespace libdap {
00045 
00046 bool D4ConstraintEvaluator::parse(const std::string &expr)
00047 {
00048         d_expr = expr;  // set for error messages. See the %initial-action section of .yy
00049 
00050         std::istringstream iss(expr);
00051         D4CEScanner scanner(iss);
00052         D4CEParser parser(scanner, *this /* driver */);
00053 
00054         if (trace_parsing()) {
00055                 parser.set_debug_level(1);
00056                 parser.set_debug_stream(std::cerr);
00057         }
00058 
00059         return parser.parse() == 0;
00060 }
00061 
00062 #if 0
00063 void
00064 D4ConstraintEvaluator::set_array_slices(const std::string &id, Array *a)
00065 {
00066     // Test that the indexes and dimensions match in number
00067     if (d_indexes.size() != a->dimensions())
00068         throw Error(malformed_expr, "The index constraint for '" + id + "' does not match its rank.");
00069 
00070     Array::Dim_iter d = a->dim_begin();
00071     for (vector<index>::iterator i = d_indexes.begin(), e = d_indexes.end(); i != e; ++i) {
00072         if ((*i).stride > (unsigned long long)a->dimension_stop(d, false))
00073             throw Error(malformed_expr, "For '" + id + "', the index stride value is greater than the number of elements in the Array");
00074         if (!(*i).rest && ((*i).stop) > (unsigned long long)a->dimension_stop(d, false))
00075             throw Error(malformed_expr, "For '" + id + "', the index stop value is greater than the number of elements in the Array");
00076 
00077         D4Dimension *dim = a->dimension_D4dim(d);
00078 
00079         // In a DAP4 CE, specifying '[]' as an array dimension slice has two meanings.
00080         // It can mean 'all the elements' of the dimension or 'apply the slicing inherited
00081         // from the shared dimension'. The latter might be provide 'all the elements'
00082         // but regardless, the Array object must record the CE correctly.
00083 
00084         if (dim && (*i).empty) {
00085             a->add_constraint(d, dim);
00086         }
00087         else {
00088             a->add_constraint(d, (*i).start, (*i).stride, (*i).rest ? -1 : (*i).stop);
00089         }
00090 
00091         ++d;
00092     }
00093 
00094     d_indexes.clear();
00095 }
00096 #endif
00097 
00098 void
00099 D4ConstraintEvaluator::throw_not_found(const string &id, const string &ident)
00100 {
00101     throw Error(no_such_variable, d_expr + ": The variable " + id + " was not found in the dataset (" + ident + ").");
00102 }
00103 
00104 void
00105 D4ConstraintEvaluator::throw_not_array(const string &id, const string &ident)
00106 {
00107         throw Error(no_such_variable, d_expr + ": The variable '" + id + "' is not an Array variable (" + ident + ").");
00108 }
00109 
00110 void
00111 D4ConstraintEvaluator::search_for_and_mark_arrays(BaseType *btp)
00112 {
00113         DBG(cerr << "Entering D4ConstraintEvaluator::search_for_and_mark_arrays...(" << btp->name() << ")" << endl);
00114 
00115         assert(btp->is_constructor_type());
00116 
00117         Constructor *ctor = static_cast<Constructor*>(btp);
00118         for (Constructor::Vars_iter i = ctor->var_begin(), e = ctor->var_end(); i != e; ++i) {
00119                 switch ((*i)->type()) {
00120                 case dods_array_c:
00121                         DBG(cerr << "Found an array: " << (*i)->name() << endl);
00122                         mark_array_variable(*i);
00123                         break;
00124                 case dods_structure_c:
00125                 case dods_sequence_c:
00126                         DBG(cerr << "Found a ctor: " << (*i)->name() << endl);
00127                         search_for_and_mark_arrays(*i);
00128                         break;
00129                 default:
00130                         break;
00131                 }
00132         }
00133 }
00134 
00144 BaseType *
00145 D4ConstraintEvaluator::mark_variable(BaseType *btp)
00146 {
00147     assert(btp);
00148 
00149     DBG(cerr << "In D4ConstraintEvaluator::mark_variable... (" << btp->name() << "; " << btp->type_name() << ")" << endl);
00150 
00151     btp->set_send_p(true);
00152 
00153     if (btp->type() == dods_array_c ) {
00154         mark_array_variable(btp);
00155     }
00156 
00157     // Test for Constructors and marks arrays they contain
00158         if (btp->is_constructor_type()) {
00159                 search_for_and_mark_arrays(btp);
00160         }
00161         else if (btp->type() == dods_array_c && btp->var() && btp->var()->is_constructor_type()) {
00162                 search_for_and_mark_arrays(btp->var());
00163         }
00164 
00165     // Now set the parent variables
00166     BaseType *parent = btp->get_parent();
00167     while (parent) {
00168         parent->BaseType::set_send_p(true); // Just set the parent using BaseType's impl.
00169         parent = parent->get_parent();
00170     }
00171 
00172     return btp;
00173 }
00174 
00187 BaseType *
00188 D4ConstraintEvaluator::mark_array_variable(BaseType *btp)
00189 {
00190         assert(btp->type() == dods_array_c);
00191 
00192         Array *a = static_cast<Array*>(btp);
00193 
00194         // If an array appears in a CE without the slicing operators ([]) we still have to
00195         // call set_user_by_projected_var(true) for all of it's sdims for them to appear in
00196         // the CDMR.
00197         if (d_indexes.empty()) {
00198             for (Array::Dim_iter d = a->dim_begin(), de = a->dim_end(); d != de; ++d) {
00199                 D4Dimension *dim = a->dimension_D4dim(d);
00200                 if (dim) {
00201                         a->add_constraint(d, dim);
00202                 }
00203             }
00204         }
00205     else {
00206         // Test that the indexes and dimensions match in number
00207         if (d_indexes.size() != a->dimensions())
00208             throw Error(malformed_expr, "The index constraint for '" + btp->name() + "' does not match its rank.");
00209 
00210         Array::Dim_iter d = a->dim_begin();
00211         for (vector<index>::iterator i = d_indexes.begin(), e = d_indexes.end(); i != e; ++i) {
00212             if ((*i).stride > (unsigned long long) (a->dimension_stop(d, false) - a->dimension_start(d, false)) + 1)
00213                 throw Error(malformed_expr, "For '" + btp->name() + "', the index stride value is greater than the number of elements in the Array");
00214             if (!(*i).rest && ((*i).stop) > (unsigned long long) (a->dimension_stop(d, false) - a->dimension_start(d, false)) + 1)
00215                 throw Error(malformed_expr, "For '" + btp->name() + "', the index stop value is greater than the number of elements in the Array");
00216 
00217             D4Dimension *dim = a->dimension_D4dim(d);
00218 
00219             // In a DAP4 CE, specifying '[]' as an array dimension slice has two meanings.
00220             // It can mean 'all the elements' of the dimension or 'apply the slicing inherited
00221             // from the shared dimension'. The latter might be provide 'all the elements'
00222             // but regardless, the Array object must record the CE correctly.
00223 
00224             if (dim && (*i).empty) {
00225                 a->add_constraint(d, dim);  // calls set_used_by_projected_var(true) + more
00226             }
00227             else {
00228                 a->add_constraint(d, (*i).start, (*i).stride, (*i).rest ? -1 : (*i).stop);
00229             }
00230 
00231             ++d;
00232         }
00233 
00234         d_indexes.clear();
00235     }
00236 
00237         return btp;
00238 }
00239 
00247 D4Dimension *
00248 D4ConstraintEvaluator::slice_dimension(const std::string &id, const index &i)
00249 {
00250     D4Dimension *dim = dmr()->root()->find_dim(id);
00251 
00252     if (i.stride > dim->size())
00253         throw Error(malformed_expr, "For '" + id + "', the index stride value is greater than the size of the dimension");
00254     if (!i.rest && (i.stop > dim->size() - 1))
00255         throw Error(malformed_expr, "For '" + id + "', the index stop value is greater than the size of the dimension");
00256 
00257     dim->set_constraint(i.start, i.stride, i.rest ? dim->size() - 1: i.stop);
00258 
00259     return dim;
00260 }
00261 
00262 D4ConstraintEvaluator::index
00263 D4ConstraintEvaluator::make_index(const std::string &i)
00264 {
00265         unsigned long long v = get_ull(i.c_str());
00266         return index(v, 1, v, false, false /*empty*/);
00267 }
00268 
00269 D4ConstraintEvaluator::index
00270 D4ConstraintEvaluator::make_index(const std::string &i, const std::string &s, const std::string &e)
00271 {
00272         return index(get_ull(i.c_str()), get_ull(s.c_str()), get_ull(e.c_str()), false, false /*empty*/);
00273 }
00274 
00275 D4ConstraintEvaluator::index
00276 D4ConstraintEvaluator::make_index(const std::string &i, unsigned long long s, const std::string &e)
00277 {
00278         return index(get_ull(i.c_str()), s, get_ull(e.c_str()), false, false /*empty*/);
00279 }
00280 
00281 D4ConstraintEvaluator::index
00282 D4ConstraintEvaluator::make_index(const std::string &i, const std::string &s)
00283 {
00284         return index(get_ull(i.c_str()), get_ull(s.c_str()), 0, true, false /*empty*/);
00285 }
00286 
00287 D4ConstraintEvaluator::index
00288 D4ConstraintEvaluator::make_index(const std::string &i, unsigned long long s)
00289 {
00290         return index(get_ull(i.c_str()), s, 0, true, false /*empty*/);
00291 }
00292 
00293 // This method is called from the parser (see d4_ce_parser.yy, down in the code
00294 // section). This will be called during the call to D4CEParser::parse(), that
00295 // is inside D4ConstraintEvaluator::parse(...)
00296 void
00297 D4ConstraintEvaluator::error(const libdap::location &l, const std::string &m)
00298 {
00299         ostringstream oss;
00300         oss << l << ": " << m << ends;
00301         throw Error(malformed_expr, oss.str());
00302 }
00303 
00304 } /* namespace libdap */