Marsyas  0.5.0-beta1
/Users/jleben/code/marsyas/src/marsyas/expr/ExVal.cpp
Go to the documentation of this file.
00001 /*
00002 ** Copyright (C) 1998-2010 George Tzanetakis <gtzan@cs.uvic.ca>
00003 **
00004 ** This program is free software; you can redistribute it and/or modify
00005 ** it under the terms of the GNU General Public License as published by
00006 ** the Free Software Foundation; either version 2 of the License, or
00007 ** (at your option) any later version.
00008 **
00009 ** This program is distributed in the hope that it will be useful,
00010 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 ** GNU General Public License for more details.
00013 **
00014 ** You should have received a copy of the GNU General Public License
00015 ** along with this program; if not, write to the Free Software
00016 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017 */
00018 
00019 #include <marsyas/expr/ExVal.h>
00020 #include <marsyas/expr/ExNode.h>
00021 
00022 using std::ostringstream;
00023 using namespace Marsyas;
00024 
00025 /******************************************************************/
00026 void
00027 ExVal::clear_list()
00028 {
00029   if (list_) {
00030     for (int i=0; i<natural_; ++i) { list_[i]->deref(); }
00031     delete [] list_;
00032     list_=NULL;
00033   }
00034 }
00035 
00036 void
00037 ExVal::clear()
00038 {
00039   clear_list();
00040   type_      ="";
00041   string_    ="";
00042   bool_      =false;
00043   natural_   =0;
00044   real_      =0.0;
00045   if (fun_) fun_->deref();
00046   fun_       =NULL;
00047   timer_     =NULL;
00048   scheduler_ =NULL;
00049   list_      =NULL;
00050 }
00051 
00052 void ExVal::set(ExFun* x) { clear(); type_=(x==NULL) ? "" : x->getType(); fun_=x; }
00053 void ExVal::set(const mrs_string x) { clear(); type_="mrs_string"; string_=x; }
00054 void ExVal::set(double x) { clear(); type_="mrs_real"; real_=x; }
00055 void ExVal::set(float x) { clear(); type_="mrs_real"; real_=x; }
00056 void ExVal::set(mrs_natural x) { clear(); type_="mrs_natural"; natural_=x; }
00057 void ExVal::set(mrs_bool x) { clear(); type_="mrs_bool"; bool_=x; }
00058 void ExVal::set(TmTimer** t) { clear(); type_="mrs_timer"; timer_=t; }
00059 void ExVal::set(Scheduler** t) { clear(); type_="mrs_scheduler"; scheduler_=t; }
00060 
00061 void
00062 ExVal::set(mrs_natural len, ExNode** xs, std::string t)
00063 {
00064   clear();
00065   if (xs!=NULL) { list_=xs; if((*xs)!=NULL&&len>0) { t=(*xs)->getType(); } }
00066   else { len=0; list_=new ExNode*[len]; }
00067   type_=t+" list"; natural_=len;
00068 }
00069 
00070 void
00071 ExVal::set(mrs_natural len, std::string t) // what is this ??
00072 {
00073   (void) len; // FIXME Unused parameter
00074   clear(); type_=t; natural_=0; list_=NULL;
00075 }
00076 
00077 void
00078 ExVal::set(const ExVal& v)
00079 {
00080   clear();
00081   kind_      =v.kind_;
00082   type_      =v.type_;
00083   string_    =v.string_;
00084   natural_   =v.natural_;
00085   real_      =v.real_;
00086   bool_      =v.bool_;
00087   fun_       =(v.fun_==NULL) ? NULL : v.fun_->copy();
00088   timer_     =v.timer_;
00089   scheduler_ =v.scheduler_;
00090   if (is_list()) { // can do this now that type_=v.type_
00091     list_=new ExNode*[natural_];
00092     for (int i=0; i<natural_; ++i) {
00093       list_[i]=v.list_[i];
00094       list_[i]->inc_ref();
00095     }
00096   }
00097   else list_=NULL;
00098 }
00099 
00100 ExVal::~ExVal()
00101 {
00102   if (fun_!=NULL) fun_->deref();
00103   clear_list();
00104 }
00105 
00106 std::string
00107 ExVal::toString() const
00108 {
00109   if (type_=="mrs_string") { return string_; }
00110   else if (type_=="mrs_real") { return dtos(real_); }
00111   else if (type_=="mrs_natural") { return ltos(natural_); }
00112   else if (type_=="mrs_bool") { return btos(bool_); }
00113   else if (type_=="mrs_fun") { return "<mrs_fun>"; }
00114   else if (type_=="mrs_timer") { return "<mrs_timer>"; }
00115   else if (type_=="mrs_scheduler") { return "<mrs_scheduler>"; }
00116   else if (type_=="") { return "unknown value"; }
00117   return type_;
00118 }
00119 
00120 ExVal
00121 ExVal::defaultExValue(std::string type)//{{{
00122 {
00123   if (type=="mrs_string") return (std::string)"";
00124   if (type=="mrs_bool") return (bool)false;
00125   if (type=="mrs_natural") return (long)0;
00126   if (type=="mrs_real") return (double)0.0;
00127   if (type=="mrs_timer") { ExVal v((TmTimer**)NULL); return v; }
00128   if (type=="mrs_scheduler") { ExVal v((Scheduler**)NULL); return v; }
00129   return ExVal();
00130 }//}}}
00131 
00132 std::string
00133 ExVal::getBaseType() const
00134 {
00135   mrs_natural p=(mrs_natural)type_.find(' ');
00136   if (p<0) return type_;
00137   return type_.substr(0,p);
00138 }
00139 
00140 std::string
00141 ExVal::getElemType() const
00142 {
00143   if (type_=="mrs_string") {
00144     return "mrs_string";
00145   }
00146   else if (is_list()) {
00147     return type_.substr(0,type_.length()-5);
00148   }
00149   return "";
00150 }
00151 
00152 bool
00153 ExVal::is_list() const
00154 { // whoa! that's crazy man..
00155   size_t len = type_.length();
00156   return (len>3)
00157          && (type_[len-4]=='l')
00158          && (type_[len-3]=='i')
00159          && (type_[len-2]=='s')
00160          && (type_[len-1]=='t');
00161 }
00162 
00163 bool
00164 ExVal::is_seq() const
00165 {
00166   return type_=="mrs_string"||is_list();
00167 }
00168 
00169 ExVal
00170 ExVal::getSeqRange(int lidx, int ridx)
00171 {
00172   if (!is_seq()) {
00173     return defaultExValue(getBaseType()); // obviously an error, but what to do?
00174   }
00175   if (lidx<0) lidx=0;
00176 
00177   mrs_natural len;
00178   if (is_list()) {
00179     len=natural_;
00180     if (len<=0||lidx>=len) { return ExVal(0,getType()); }
00181 
00182     if (ridx<lidx) ridx=lidx;
00183     else if (ridx>=len) ridx=len-1;
00184     mrs_natural new_len=ridx-lidx;
00185 
00186     ExNode** new_list=new ExNode*[new_len];
00187     int p=0;
00188     for (int i=lidx; i<ridx; ++i) {
00189       ExNode* e=list_[i];
00190       new_list[p]=e; p++;
00191       e->inc_ref();
00192     }
00193     return ExVal(new_len,(ExNode**)new_list);
00194   }
00195   else { // mrs_string
00196     len=(mrs_natural)string_.length();
00197     if (len<=0||lidx>=len) { return (std::string)""; }
00198 
00199     if (ridx<lidx) ridx=lidx;
00200     else if (ridx>=len) ridx=len-1;
00201 
00202     return (std::string)string_.substr(lidx,ridx-1);
00203   }
00204 }
00205 
00206 ExVal
00207 ExVal::getSeqElem(int idx)
00208 {
00209   if (is_list()) {
00210     if (idx>=natural_||idx<0) {
00211       MRSWARN("ExVal::getSeqElem  index exceeds list length");
00212       return defaultExValue(getBaseType());
00213     }
00214     return list_[idx]->eval();
00215   }
00216   else if (type_=="mrs_string") {
00217     if (idx>=0&&idx<=(int)string_.length())
00218       return (std::string)string_.substr(idx,1);
00219     return (std::string)"";
00220   }
00221   else {
00222     MRSWARN("ExVal::getSeqElem  element access on non-sequence type: "+type_);
00223     return defaultExValue(getBaseType());
00224   }
00225 }
00226 
00227 void
00228 ExVal::setSeqElem(int idx, ExVal v)
00229 {
00230   if (idx<0||idx>=natural_) {
00231     MRSWARN("ExVal::set[]  Index out of bounds");
00232     return;
00233   }
00234   list_[idx]->deref();
00235   list_[idx]=new ExNode(v);
00236 }
00237 
00238 namespace Marsyas {
00239 std::ostream&
00240 operator<<(std::ostream& o, ExVal& v)
00241 {
00242   bool i_am_a_list = v.is_list();
00243   if (i_am_a_list) {
00244     o<<"[";
00245     for (int i=0; i<v.natural_; ++i) {
00246       ExVal x=v.list_[i]->eval();
00247       o<<x;
00248       if (i<v.natural_-1) { o<<", "; }
00249     }
00250     o<<"]";
00251   }
00252   else if (v.type_=="mrs_string") o<<"'"<<v.string_<<"'";
00253   else if (v.type_=="mrs_natural") o<<ltos(v.natural_);
00254   else if (v.type_=="mrs_real") o<<dtos(v.real_);
00255   else if (v.type_=="mrs_bool") o<<btos(v.bool_);
00256   return o;
00257 }
00258 }
00259 
00260 ExVal
00261 ExVal::append(const ExVal v) const
00262 {
00263   if (!is_list()||!v.is_list()) {
00264     MRSWARN("ExVal::append  only sequence types may be appended: "+getType()+", "+v.getType());
00265     return *this;
00266   }
00267   if (getType()==" list"||v.getType()==" list"||getType()==v.getType()) {
00268     mrs_natural len=natural_+v.toNatural(); ExNode** elems=new ExNode*[len];
00269     int l=0;
00270     if (natural_>0) {
00271       for (int i=0; i<natural_; ++i,l++) {
00272         elems[l]=list_[i];
00273         elems[l]->inc_ref();
00274       }
00275     }
00276     if (v.toNatural()>0) {
00277       for (int i=0; i<v.toNatural(); ++i,l++) {
00278         elems[l]=v.list_[i];
00279         elems[l]->inc_ref();
00280       }
00281     }
00282     return ExVal(len,elems);
00283   }
00284   MRSWARN("ExVal::append  type mismatch in list concat: "+getType()+","+v.getType());
00285   return *this;
00286 }