--- /dev/null
+/************************************************************************
+ ************************************************************************
+ FAUST compiler
+ Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ************************************************************************
+ ************************************************************************/
+
+
+
+#include "tree.hh"
+#include "sigtype.hh"
+#include "property.hh"
+
+int AudioType::gAllocationCount = 0;
+
+bool SimpleType::isMaximal() const ///< true when type is maximal (and therefore can't change depending of hypothesis)
+{
+ return (fNature==kReal)
+ && (fVariability==kSamp)
+ && (fComputability==kExec);
+
+}
+
+
+//------------------------------------------------------------------------------------
+//
+// Surcharges de l'operateur d'impression <<
+//
+//------------------------------------------------------------------------------------
+
+
+ostream& operator<<(ostream& dst, const Type& t) { return t->print(dst);}
+
+ostream& operator<<(ostream& dst, const SimpleType& t) { return t.print(dst); }
+
+ostream& operator<<(ostream& dst, const TableType& t) { return t.print(dst); }
+
+ostream& operator<<(ostream& dst, const TupletType& t) { return t.print(dst); }
+
+ostream& operator<<(ostream& dst, const VectorType& t) { return t.print(dst); }
+
+
+//------------------------------------------------------------------------------------
+//
+// Definition des methodes d'impression
+//
+//------------------------------------------------------------------------------------
+
+
+/**
+ * Print the content of a simple type on a stream
+ */
+ostream& SimpleType::print(ostream& dst) const
+{
+ return dst << "NR"[nature()]
+ << "KB?S"[variability()]
+ << "CI?E"[computability()]
+ << "VS?TS"[vectorability()]
+ << "N?B"[boolean()]
+ << " " << fInterval;
+}
+
+
+/**
+ * Print the content of a table type on a stream
+ */
+ostream& TableType::print(ostream& dst) const
+{
+ dst << "KB?S"[variability()]
+ << "CI?E"[computability()]
+ << " " << fInterval
+ << ":Table(";
+ fContent->print(dst);
+ return dst << ')';
+}
+
+
+/**
+ * true when type is maximal (and therefore can't change depending of hypothesis)
+ */
+bool TableType::isMaximal() const
+{
+ return (fNature==kReal)
+ && (fVariability==kSamp)
+ && (fComputability==kExec);
+}
+
+
+
+/**
+ * Print the content of a tuplet of types on a stream
+ */
+ostream& TupletType::print(ostream& dst) const
+{
+ dst << "KB?S"[variability()]
+ << "CI?E"[computability()]
+ << " " << fInterval
+ << " : {";
+ string sep = "";
+ for (unsigned int i = 0; i < fComponents.size(); i++, sep="*") {
+ dst << sep;
+ fComponents[i]->print(dst);
+ }
+ dst << '}';
+ return dst;
+}
+
+
+
+/**
+ * Print the content of a vector type on a stream
+ */
+ostream& VectorType::print(ostream& dst) const
+{
+ dst << "vector[" << fSize << "," << fContent << "]";
+ return dst;
+}
+
+
+/**
+ * true when type is maximal (and therefore can't change depending of hypothesis)
+ */
+bool TupletType::isMaximal() const
+{
+ for (unsigned int i = 0; i < fComponents.size(); i++) {
+ if (! fComponents[i]->isMaximal()) return false;
+ }
+ return true;
+}
+
+
+//------------------------------------------------------------------------------------
+//
+// Construction des types
+// t := p, table(t), t|t, t*t
+//
+//------------------------------------------------------------------------------------
+
+// Essential predefined types
+
+Type TINT = makeSimpleType(kInt, kKonst, kComp, kVect, kNum, interval());
+Type TREAL = makeSimpleType(kReal, kKonst, kComp, kVect, kNum, interval());
+
+Type TKONST = makeSimpleType(kInt, kKonst, kComp, kVect, kNum, interval());
+Type TBLOCK = makeSimpleType(kInt, kBlock, kComp, kVect, kNum, interval());
+Type TSAMP = makeSimpleType(kInt, kSamp, kComp, kVect, kNum, interval());
+
+Type TCOMP = makeSimpleType(kInt, kKonst, kComp, kVect, kNum, interval());
+Type TINIT = makeSimpleType(kInt, kKonst, kInit, kVect, kNum, interval());
+Type TEXEC = makeSimpleType(kInt, kKonst, kExec, kVect, kNum, interval());
+
+// more predefined types
+
+Type TINPUT = makeSimpleType(kReal, kSamp, kExec, kVect, kNum, interval());
+Type TGUI = makeSimpleType(kReal, kBlock,kExec, kVect, kNum, interval());
+Type TGUI01 = makeSimpleType(kReal, kBlock,kExec, kVect, kNum, interval(0,1));
+Type INT_TGUI = makeSimpleType(kInt, kBlock,kExec, kVect, kNum, interval());
+//Type TREC = makeSimpleType(kInt, kSamp, kInit, kVect, kNum, interval()); // kVect ou kScal ?
+
+// trying to accelerate type convergence
+//Type TREC = TINT;
+Type TREC = makeSimpleType(kInt, kSamp, kInit, kScal, kNum, interval()); // kVect ou kScal ?
+
+
+Type operator| ( const Type& t1, const Type& t2)
+{
+ SimpleType *st1, *st2;
+ TableType *tt1, *tt2;
+ TupletType *nt1, *nt2;
+
+ if ( (st1 = isSimpleType(t1)) && (st2 = isSimpleType(t2)) ) {
+
+ return makeSimpleType( st1->nature()|st2->nature(),
+ st1->variability()|st2->variability(),
+ st1->computability()|st2->computability(),
+ st1->vectorability()|st2->vectorability(),
+ st1->boolean()|st2->boolean(),
+ reunion(st1->getInterval(), st2->getInterval())
+ );
+
+ } else if ( (tt1 = isTableType(t1)) && (tt2 = isTableType(t2)) ) {
+
+ return makeTableType( tt1->content() | tt2->content() );
+
+ } else if ( (nt1 = isTupletType(t1)) && (nt2 = isTupletType(t2)) ) {
+
+ vector<Type> v;
+ int n = min(nt1->arity(), nt2->arity());
+ for (int i=0; i<n; i++) { v.push_back( (*nt1)[i] | (*nt2)[i]); }
+ return new TupletType( v );
+
+ } else {
+
+ vector<int> D1, D2, D3;
+ Type b1 = t1->dimensions(D1);
+ Type b2 = t2->dimensions(D2);
+ if (maxdimensions(D1, D2, D3)) {
+ Type b3 = b1|b2;
+ return makeVectorType(b3, D3);
+ }
+
+ cerr << "Error : trying to combine incompatible types, " << t1 << " and " << t2 << endl;
+ exit(1);
+ return 0;
+ }
+}
+
+bool operator== ( const Type& t1, const Type& t2)
+{
+ SimpleType *st1, *st2;
+ TableType *tt1, *tt2;
+ TupletType *nt1, *nt2;
+ VectorType *vt1, *vt2;
+
+ if (t1->variability() != t2->variability()) return false;
+ if (t1->computability() != t2->computability()) return false;
+
+ if ( (st1 = isSimpleType(t1)) && (st2 = isSimpleType(t2)) )
+ return (st1->nature() == st2->nature())
+ && (st1->variability() == st2->variability())
+ && (st1->computability() == st2->computability())
+ && (st1->vectorability() == st2->vectorability())
+ && (st1->boolean() == st2->boolean())
+ && (st1->getInterval().lo == st2->getInterval().lo)
+ && (st1->getInterval().hi == st2->getInterval().hi)
+ && (st1->getInterval().valid == st2->getInterval().valid);
+ if ( (tt1 = isTableType(t1)) && (tt2 = isTableType(t2)) )
+ return tt1->content()== tt2->content();
+ if ( (nt1 = isTupletType(t1)) && (nt2 = isTupletType(t2)) ) {
+ int a1 = nt1->arity();
+ int a2 = nt2->arity();
+ if (a1 == a2) {
+ for (int i=0; i<a1; i++) { if ((*nt1)[i] != (*nt2)[i]) return false; }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // compare vector types
+ if ( (vt1 = isVectorType(t1)) && (vt2 = isVectorType(t2)) ) {
+ if (vt1->size() == vt2->size()) {
+ return vt1->content() == vt2->content();
+ } else {
+ return false;
+ }
+ }
+
+ // types are different
+ return false;
+}
+
+bool operator<= ( const Type& t1, const Type& t2)
+{
+ return (t1|t2) == t2;
+}
+
+
+
+Type operator* (const Type& t1, const Type& t2)
+{
+ vector<Type> v;
+
+ TupletType* nt1 = dynamic_cast<TupletType*>((AudioType*)t1);
+ TupletType* nt2 = dynamic_cast<TupletType*>((AudioType*)t2);
+
+ if (nt1) {
+ for (int i=0; i<nt1->arity(); i++) {
+ v.push_back((*nt1)[i]);
+ }
+ } else {
+ v.push_back(t1);
+ }
+
+ if (nt2) {
+ for (int i=0; i<nt2->arity(); i++) {
+ v.push_back((*nt2)[i]);
+ }
+ } else {
+ v.push_back(t2);
+ }
+ return new TupletType(v);
+}
+
+
+SimpleType* isSimpleType(AudioType* t) { return dynamic_cast<SimpleType*>(t); }
+TableType* isTableType(AudioType* t) { return dynamic_cast<TableType*>(t); }
+TupletType* isTupletType(AudioType* t) { return dynamic_cast<TupletType*>(t); }
+VectorType* isVectorType(AudioType* t) { return dynamic_cast<VectorType*>(t); }
+
+
+
+//--------------------------------------------------
+// verification de type
+
+Type checkInt(Type t)
+{
+ // verifie que t est entier
+ SimpleType* st = isSimpleType(t);
+ if (st == 0 || st->nature() > kInt) {
+ cerr << "Error : checkInt failed for type " << t << endl;
+ exit(1);
+ }
+ return t;
+}
+
+Type checkKonst(Type t)
+{
+ // verifie que t est constant
+ if (t->variability() > kKonst) {
+ cerr << "Error : checkKonst failed for type " << t << endl;
+ exit(1);
+ }
+ return t;
+}
+
+Type checkInit(Type t)
+{
+ // verifie que t est connu a l'initialisation
+ if (t->computability() > kInit) {
+ cerr << "Error : checkInit failed for type " << t << endl;
+ exit(1);
+ }
+ return t;
+}
+
+Type checkIntParam(Type t)
+{
+ return checkInit(checkKonst(checkInt(t)));
+}
+
+Type checkWRTbl(Type tbl, Type wr)
+{
+ // verifie que wr est compatible avec le contenu de tbl
+ if (wr->nature() > tbl->nature()) {
+ cerr << "Error : checkWRTbl failed, the content of " << tbl << " is incompatible with " << wr << endl;
+ exit(1);
+ }
+ return tbl;
+}
+
+/**
+ \brief Check is a type is appropriate for a delay.
+ @return -1 if not appropriate, mxd (max delay) if appropriate
+
+ */
+int checkDelayInterval(Type t)
+{
+ interval i = t->getInterval();
+ if (i.valid && i.lo >= 0) {
+ return int(i.hi+0.5);
+ } else {
+ //cerr << "checkDelayInterval failed for : " << i << endl;
+ return -1;
+ }
+}
+
+
+// Donne le nom du type C correspondant �la nature d'un signal
+string cType (Type t)
+{
+ return (t->nature() == kInt) ? "int" : "float";
+}
+
+
+
+/*****************************************************************************
+ *
+ * codeAudioType(Type) -> Tree
+ * Code an audio type as a tree in order to benefit of memoization
+ *
+ *****************************************************************************/
+
+// memoized type contruction
+
+property<AudioType*> MemoizedTypes;
+
+
+Sym SIMPLETYPE = symbol ("SimpleType");
+Sym TABLETYPE = symbol ("TableType");
+Sym TUPLETTYPE = symbol ("TupletType");
+Sym VECTORTYPE = symbol ("VectorType");
+
+static Tree codeSimpleType(SimpleType* st);
+static Tree codeTableType(TableType* st);
+static Tree codeTupletType(TupletType* st);
+static Tree codeVectorType(VectorType* st);
+
+
+/**
+ * codeAudioType(Type) -> Tree
+ * Code an audio type as a tree in order to benefit of memoization
+ * The type field (of the coded type) is used to store the audio
+ * type
+ */
+Tree codeAudioType(AudioType* t)
+{
+ SimpleType* st;
+ TableType* tt;
+ TupletType* nt;
+ VectorType* vt;
+
+ Tree r;
+
+ if ((r=t->getCode())) return r;
+
+ if ((st = isSimpleType(t))) {
+ r = codeSimpleType(st);
+ } else if ((tt = isTableType(t))) {
+ r = codeTableType(tt);
+ } else if ((nt = isTupletType(t))) {
+ r = codeTupletType(nt);
+ } else if ((vt = isVectorType(t))) {
+ r = codeVectorType(vt);
+ } else {
+ cerr << "ERROR in codeAudioType() : invalide pointer " << t << endl;
+ exit(1);
+ }
+
+ r->setType(t);
+ return r;
+
+}
+
+
+/**
+ * Code a simple audio type as a tree in order to benefit of memoization
+ */
+static Tree codeSimpleType(SimpleType* st)
+{
+ vector<Tree> elems;
+ elems.push_back(tree(st->nature()));
+ elems.push_back(tree(st->variability()));
+ elems.push_back(tree(st->computability()));
+ elems.push_back(tree(st->vectorability()));
+ elems.push_back(tree(st->boolean()));
+
+ elems.push_back(tree(st->getInterval().valid));
+ elems.push_back(tree(st->getInterval().lo));
+ elems.push_back(tree(st->getInterval().hi));
+
+ return CTree::make(SIMPLETYPE, elems);
+
+}
+
+AudioType* makeSimpleType(int n, int v, int c, int vec, int b, const interval& i)
+{
+ SimpleType prototype(n,v,c,vec,b,i);
+ Tree code = codeAudioType(&prototype);
+
+ AudioType* t;
+ if (MemoizedTypes.get(code, t)) {
+ return t;
+ } else {
+ AudioType::gAllocationCount++;
+ t = new SimpleType(n,v,c,vec,b,i);
+ MemoizedTypes.set(code, t);
+ t->setCode(code);
+ return t;
+ }
+}
+
+
+/**
+ * Code a table type as a tree in order to benefit of memoization
+ */
+
+static Tree codeTableType(TableType* tt)
+{
+ return tree(TABLETYPE, codeAudioType(tt->content()));
+}
+
+AudioType* makeTableType(const Type& ct)
+{
+ TableType prototype(ct);
+ Tree code = codeAudioType(&prototype);
+
+ AudioType* tt;
+ if (MemoizedTypes.get(code, tt)) {
+ return tt;
+ } else {
+ AudioType::gAllocationCount++;
+ tt = new TableType(ct);
+ MemoizedTypes.set(code, tt);
+ tt->setCode(code);
+ return tt;
+ }
+}
+
+AudioType* makeTableType(const Type& ct, int n, int v, int c, int vec, int b, const interval& i)
+{
+ TableType prototype(ct,n,v,c,vec,b,i);
+ Tree code = codeAudioType(&prototype);
+
+ AudioType* tt;
+ if (MemoizedTypes.get(code, tt)) {
+ return tt;
+ } else {
+ AudioType::gAllocationCount++;
+ tt = new TableType(ct);
+ MemoizedTypes.set(code, tt);
+ tt->setCode(code);
+ return tt;
+ }
+}
+
+AudioType* makeTableType(const Type& ct, int n, int v, int c, int vec)
+{
+ TableType prototype(ct,n,v,c,vec);
+ Tree code = codeAudioType(&prototype);
+
+ AudioType* tt;
+ if (MemoizedTypes.get(code, tt)) {
+ return tt;
+ } else {
+ AudioType::gAllocationCount++;
+ tt = new TableType(ct);
+ MemoizedTypes.set(code, tt);
+ tt->setCode(code);
+ return tt;
+ }
+}
+
+
+/**
+ * Code a tuplet type as a tree in order to benefit of memoization
+ */
+
+static Tree codeTupletType(TupletType* nt)
+{
+ vector<Tree> elems;
+ for (int i=0; i<nt->arity(); i++) {
+ elems.push_back(codeAudioType((*nt)[i]));
+ }
+ return CTree::make(TUPLETTYPE, elems);
+}
+
+AudioType* makeTupletType(const vector<Type>& vt)
+{
+ TupletType prototype(vt);
+ Tree code = codeAudioType(&prototype);
+
+ AudioType* t;
+ if (MemoizedTypes.get(code, t)) {
+ return t;
+ } else {
+ AudioType::gAllocationCount++;
+ t = new TupletType(vt);
+ MemoizedTypes.set(code, t);
+ t->setCode(code);
+ return t;
+ }
+
+}
+
+AudioType* makeTupletType(const vector<Type>& vt, int n, int v, int c, int vec, int b, const interval& i)
+{
+ TupletType prototype(vt,n,v,c,vec,b,i);
+ Tree code = codeAudioType(&prototype);
+
+ AudioType* t;
+ if (MemoizedTypes.get(code, t)) {
+ return t;
+ } else {
+ AudioType::gAllocationCount++;
+ t = new TupletType(vt,n,v,c,vec,b,i);
+ MemoizedTypes.set(code, t);
+ t->setCode(code);
+ return t;
+ }
+
+}
+
+/**
+ * Code a vector type as a tree in order to benefit of memoization
+ */
+
+static Tree codeVectorType(VectorType* vt)
+{
+ assert(vt);
+ //cerr << "codeVectorType(" << *vt << ")" << endl;
+ int i = vt->size();
+ return tree(VECTORTYPE, tree(i), codeAudioType(vt->content()));
+}
+
+Type makeVectorType(const Type& b, const vector<int>& dim)
+{
+ Type r = b;
+ for (unsigned int i=0; i<dim.size(); i++) r = new VectorType(dim[i],r);
+ return r;
+}
+
+
+/**
+ * Returns true if D1 and D2 are compatible (one is the prefix of the other)).
+ * In this case D3 contains the longuest vector D1 or D2
+ */
+bool maxdimensions(const vector<int>& D1, const vector<int>& D2, vector<int>& D3)
+{
+ unsigned int n1 = D1.size();
+ unsigned int n2 = D2.size();
+ unsigned int i = 0;
+ while ( (i<n1) && (i<n2) && (D1[i]==D2[i]) ) i++;
+ if (i==n1) {
+ D3=D2;
+ return true;
+ } else if (i==n2) {
+ D3=D1;
+ return true;
+ } else {
+ return false;
+ }
+}