/** * Try to open the file '<dir>/<path>/<filename>'. If it succeed, it stores the full pathname * of the file into <fullpath> */ static FILE* fopenat(string& fullpath, const string& dir, const char* path, const char* filename) { int err; char olddirbuffer[FAUST_PATH_MAX]; char newdirbuffer[FAUST_PATH_MAX]; char* olddir = getcwd(olddirbuffer, FAUST_PATH_MAX); if (chdir(dir.c_str()) == 0) { if (chdir(path) == 0) { FILE* f = fopen(filename, "r"); char* newdir = getcwd(newdirbuffer, FAUST_PATH_MAX); if (!newdir) { stringstream error; error << "ERROR : getcwd '" << strerror(errno) << endl; throw faustexception(error.str()); } fullpath = newdir; fullpath += '/'; fullpath += filename; err = chdir(olddir); return f; } } err = chdir(olddir); if (err != 0) { stringstream error; error << "ERROR : cannot change back directory to '" << olddir << "' : " << strerror(errno) << endl; throw faustexception(error.str()); } return 0; }
/** * 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; 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 { stringstream error; error << "ERROR in codeAudioType() : invalide pointer " << t << endl; throw faustexception(error.str()); } r->setType(t); return r; }
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 { stringstream error; error << "Error : trying to combine incompatible types, " << t1 << " and " << t2 << endl; throw faustexception(error.str()); } }
Tree buildBoxAppl (Tree fun, Tree revarglist) { if (isNil (revarglist)) { // a revoir !!!!!! throw faustexception("ERROR : buildBoxAppl called with null revarglist\n"); } return boxAppl(fun, revarglist); }
/** * Generate a "iota" time function, n-cyclical. */ string DocCompiler::generateIota (Tree sig, Tree n) { int size; if (!isSigInt(n, &size)) { throw faustexception("ERROR in generateIota\n"); } //cout << "iota !" << endl; return subst(" t \\bmod{$0} ", docT(size)); }
Type checkInit(Type t) { // verifie que t est connu a l'initialisation if (t->computability() > kInit) { stringstream error; error << "Error : checkInit failed for type " << t << endl; throw faustexception(error.str()); } return t; }
Type checkKonst(Type t) { // verifie que t est constant if (t->variability() > kKonst) { stringstream error; error << "Error : checkKonst failed for type " << t << endl; throw faustexception(error.str()); } return t; }
/** * Switch back to the previously stored current directory */ static int cholddir () { if (chdir(gGlobal->gCurrentDir.c_str()) == 0) { return 0; } else { stringstream error; error << "ERROR in cholddir " << strerror(errno) << endl; throw faustexception(error.str()); } }
Type checkWRTbl(Type tbl, Type wr) { // verifie que wr est compatible avec le contenu de tbl if (wr->nature() > tbl->nature()) { stringstream error; error << "Error : checkWRTbl failed, the content of " << tbl << " is incompatible with " << wr << endl; throw faustexception(error.str()); } return tbl; }
/** * @brief Main code generator dispatch. * * According to the type of the input signal, generateCode calls * the appropriate generator with appropriate arguments. * * @param sig The signal expression to compile. * @param priority The environment priority of the expression. * @return <string> The LaTeX code translation of the signal. */ string DocCompiler::generateCode (Tree sig, int priority) { int i; double r; Tree c, sel, x, y, z, u, label, ff, largs, type, name, file; if ( getUserData(sig) ) { printGCCall(sig,"generateXtended"); return generateXtended (sig, priority); } else if ( isSigInt(sig, &i) ) { printGCCall(sig,"generateNumber"); return generateNumber (sig, docT(i)); } else if ( isSigReal(sig, &r) ) { printGCCall(sig,"generateNumber"); return generateNumber (sig, docT(r)); } else if ( isSigInput(sig, &i) ) { printGCCall(sig,"generateInput"); return generateInput (sig, docT(i+1)); } else if ( isSigOutput(sig, &i, x) ) { printGCCall(sig,"generateOutput"); return generateOutput (sig, docT(i+1), CS(x, priority)); } else if ( isSigFixDelay(sig, x, y) ) { printGCCall(sig,"generateFixDelay"); return generateFixDelay (sig, x, y, priority); } else if ( isSigPrefix(sig, x, y) ) { printGCCall(sig,"generatePrefix"); return generatePrefix (sig, x, y, priority); } else if ( isSigIota(sig, x) ) { printGCCall(sig,"generateIota"); return generateIota (sig, x); } else if ( isSigBinOp(sig, &i, x, y) ) { printGCCall(sig,"generateBinOp"); return generateBinOp (sig, i, x, y, priority); } else if ( isSigFFun(sig, ff, largs) ) { printGCCall(sig,"generateFFun"); return generateFFun (sig, ff, largs, priority); } else if ( isSigFConst(sig, type, name, file) ) { printGCCall(sig,"generateFConst"); return generateFConst (sig, tree2str(file), tree2str(name)); } else if ( isSigFVar(sig, type, name, file) ) { printGCCall(sig,"generateFVar"); return generateFVar (sig, tree2str(file), tree2str(name)); } // new special tables for documentation purposes else if ( isSigDocConstantTbl(sig, x, y) ) { printGCCall(sig,"generateDocConstantTbl"); return generateDocConstantTbl (sig, x, y); } else if ( isSigDocWriteTbl(sig,x,y,z,u) ) { printGCCall(sig,"generateDocWriteTbl"); return generateDocWriteTbl (sig, x, y, z, u); } else if ( isSigDocAccessTbl(sig, x, y) ) { printGCCall(sig, "generateDocAccessTbl"); return generateDocAccessTbl(sig, x, y); } else if ( isSigSelect2(sig, sel, x, y) ) { printGCCall(sig,"generateSelect2"); return generateSelect2 (sig, sel, x, y, priority); } else if ( isSigSelect3(sig, sel, x, y, z) ) { printGCCall(sig,"generateSelect3"); return generateSelect3 (sig, sel, x, y, z, priority); } else if ( isProj(sig, &i, x) ) { printGCCall(sig,"generateRecProj"); return generateRecProj (sig, x, i, priority); } else if ( isSigIntCast(sig, x) ) { printGCCall(sig,"generateIntCast"); return generateIntCast (sig, x, priority); } else if ( isSigFloatCast(sig, x) ) { printGCCall(sig,"generateFloatCast"); return generateFloatCast(sig, x, priority); } else if ( isSigButton(sig, label) ) { printGCCall(sig,"generateButton"); return generateButton (sig, label); } else if ( isSigCheckbox(sig, label) ) { printGCCall(sig,"generateCheckbox"); return generateCheckbox (sig, label); } else if ( isSigVSlider(sig, label,c,x,y,z) ) { printGCCall(sig,"generateVSlider"); return generateVSlider (sig, label, c,x,y,z); } else if ( isSigHSlider(sig, label,c,x,y,z) ) { printGCCall(sig,"generateHSlider"); return generateHSlider (sig, label, c,x,y,z); } else if ( isSigNumEntry(sig, label,c,x,y,z) ) { printGCCall(sig,"generateNumEntry"); return generateNumEntry (sig, label, c,x,y,z); } else if ( isSigVBargraph(sig, label,x,y,z) ) { printGCCall(sig,"generateVBargraph"); return CS(z, priority);}//generateVBargraph (sig, label, x, y, CS(z, priority)); } else if ( isSigHBargraph(sig, label,x,y,z) ) { printGCCall(sig,"generateHBargraph"); return CS(z, priority);}//generateHBargraph (sig, label, x, y, CS(z, priority)); } else if ( isSigAttach(sig, x, y) ) { printGCCall(sig,"generateAttach"); return generateAttach (sig, x, y, priority); } else if ( isSigEnable(sig, x, y) ) { printGCCall(sig,"generateEnable"); return generateEnable (sig, x, y, priority); } else { stringstream error; error << "ERROR in d signal, unrecognized signal : " << *sig << endl; throw faustexception(error.str()); } faustassert(0); return "error in generate code"; }
Type checkInt(Type t) { // verifie que t est entier SimpleType* st = isSimpleType(t); if (st == 0 || st->nature() > kInt) { stringstream error; error << "Error : checkInt failed for type " << t << endl; throw faustexception(error.str()); } return t; }
bool check_url(const char* filename) { char* fileBuf = 0; // Tries to open as an URL for a local file if (strstr(filename, "file://") != 0) { // Tries to open as a regular file after removing 'file://' FILE* f = fopen(&filename[7], "r"); if (f) { fclose(f); return true; } else { stringstream error; error << "ERROR : cannot open file '" << filename << "' : " << http_strerror() << "; for help type \"faust --help\"" << endl; throw faustexception(error.str()); } // Tries to open as a http URL } else if (strstr(filename, "http://") != 0) { if (http_fetch(filename, &fileBuf) != -1) { return true; } else { stringstream error; error << "ERROR : unable to access URL '" << filename << "' : " << http_strerror() << "; for help type \"faust --help\"" << endl; throw faustexception(error.str()); } } else { // Otherwise tries to open as a regular file FILE* f = fopen(filename, "r"); if (f) { fclose(f); return true; } else { stringstream error; error << "ERROR : cannot open file '" << filename << "' : " << strerror(errno) << "; for help type \"faust --help\"" << endl; throw faustexception(error.str()); } } }
/** * Open architecture file. */ static istream* openArchFile (const string& filename) { istream* file; getCurrentDir(); // Save the current directory. if ( (file = open_arch_stream(filename.c_str())) ) { //cerr << "Documentator : openArchFile : Opening '" << filename << "'" << endl; } else { stringstream error; error << "ERROR : can't open architecture file " << filename << endl; throw faustexception(error.str()); } cholddir(); // Return to current directory. return file; }
string DocCompiler::generateCacheCode(Tree sig, const string& exp) { //cerr << "!! entering generateCacheCode with sig=\"" << ppsig(sig) << "\"" << endl; string vname, ctype, code, vectorname; int sharing = getSharingCount(sig); Occurences* o = fOccMarkup.retrieve(sig); // check reentrance if (getCompiledExpression(sig, code)) { //cerr << "!! generateCacheCode called a true getCompiledExpression" << endl; return code; } // check for expression occuring in delays if (o->getMaxDelay()>0) { if (getVectorNameProperty(sig, vectorname)) { return exp; } getTypedNames(getCertifiedSigType(sig), "r", ctype, vname); gGlobal->gDocNoticeFlagMap["recursigs"] = true; //cerr << "- r : generateCacheCode : vame=\"" << vname << "\", for sig=\"" << ppsig(sig) << "\"" << endl; if (sharing>1) { //cerr << " generateCacheCode calls generateDelayVec(generateVariableStore) on vame=\"" << vname << "\"" << endl; return generateDelayVec(sig, generateVariableStore(sig,exp), ctype, vname, o->getMaxDelay()); } else { //cerr << " generateCacheCode calls generateDelayVec(exp) on vame=\"" << vname << "\"" << endl; return generateDelayVec(sig, exp, ctype, vname, o->getMaxDelay()); } } else if (sharing == 1 || getVectorNameProperty(sig, vectorname) || isVerySimpleFormula(sig)) { //cerr << "! generateCacheCode : sharing == 1 : return \"" << exp << "\"" << endl; return exp; } else if (sharing > 1) { //cerr << "! generateCacheCode : sharing > 1 : return \"" << exp << "\"" << endl; return generateVariableStore(sig, exp); } else { stringstream error; error << "ERROR in sharing count (" << sharing << ") for " << *sig << endl; throw faustexception(error.str()); } return "Error in generateCacheCode"; }
/** * Build a full pathname of <filename>. * <fullpath> = <currentdir>/<filename> */ static void buildFullPathname(string& fullpath, const char* filename) { char old[FAUST_PATH_MAX]; if (isAbsolutePathname(filename)) { fullpath = filename; } else { char* newdir = getcwd(old, FAUST_PATH_MAX); if (!newdir) { stringstream error; error << "ERROR : getcwd '" << strerror(errno) << endl; throw faustexception(error.str()); } fullpath = newdir; fullpath += '/'; fullpath += filename; } }
/** * Try to do a numeric simplification of a block-diagram */ Tree numericBoxSimplification(Tree box) { int ins, outs; Tree result; int i; double x; if (!getBoxType(box, &ins, &outs)) { stringstream error; error << "ERROR in file " << __FILE__ << ':' << __LINE__ << ", Can't compute the box type of : " << *box << endl; throw faustexception(error.str()); } if (ins==0 && outs==1) { // this box can potentially denote a number if (isBoxInt(box, &i) || isBoxReal(box, &x)) { result = box; } else { // propagate signals to discover if it simplifies to a number int i; double x; Tree lsignals = boxPropagateSig(gGlobal->nil, box , makeSigInputList(0)); Tree s = simplify(hd(lsignals)); if (isSigReal(s, &x)) { result = boxReal(x); } else if (isSigInt(s, &i)) { result = boxInt(i); } else { result = insideBoxSimplification(box); } } } else { // this box can't denote a number result = insideBoxSimplification(box); } return result; }
siglist realPropagate (Tree slotenv, Tree path, Tree box, const siglist& lsig) { int i; double r; prim0 p0; prim1 p1; prim2 p2; prim3 p3; prim4 p4; prim5 p5; Tree t1, t2, ff, label, cur, min, max, step, type, name, file, slot, body, chan; tvec wf; xtended* xt = (xtended*)getUserData(box); // Extended Primitives if (xt) { faustassert(lsig.size() == xt->arity()); return makeList(xt->computeSigOutput(lsig)); } // Numbers and Constants else if (isBoxInt(box, &i)) { faustassert(lsig.size()==0); return makeList(sigInt(i)); } else if (isBoxReal(box, &r)) { faustassert(lsig.size()==0); return makeList(sigReal(r)); } // A Waveform has two outputs it size and a period signal representing its content else if (isBoxWaveform(box)) { faustassert(lsig.size()==0); const tvec br = box->branches(); return listConcat(makeList(sigInt(int(br.size()))), makeList(sigWaveform(br))); } else if (isBoxFConst(box, type, name, file)) { faustassert(lsig.size()==0); return makeList(sigFConst(type, name, file)); } else if (isBoxFVar(box, type, name, file)) { faustassert(lsig.size()==0); return makeList(sigFVar(type, name, file)); } // Wire and Cut else if (isBoxCut(box)) { faustassert(lsig.size()==1); return siglist(); } else if (isBoxWire(box)) { faustassert(lsig.size()==1); return lsig; } // Slots and Symbolic Boxes else if (isBoxSlot(box)) { Tree sig; faustassert(lsig.size()==0); if (!searchEnv(box,sig,slotenv)) { // test YO simplification des diagrames //fprintf(stderr, "propagate : internal error (slot undefined)\n"); sig = sigInput(++gGlobal->gDummyInput); } return makeList(sig); } else if (isBoxSymbolic(box, slot, body)) { faustassert(lsig.size()>0); return propagate(pushEnv(slot,lsig[0],slotenv), path, body, listRange(lsig, 1, (int)lsig.size())); } // Primitives else if (isBoxPrim0(box, &p0)) { faustassert(lsig.size()==0); return makeList(p0()); } else if (isBoxPrim1(box, &p1)) { faustassert(lsig.size()==1); return makeList(p1(lsig[0])); } else if (isBoxPrim2(box, &p2)) { // printf("prim2 recoit : "); print(lsig); printf("\n"); faustassert(lsig.size()==2); if (p2 == &sigEnable) { if (gGlobal->gEnableFlag) { // special case for sigEnable that requires a transformation // enable(X,Y) -> sigEnable(X*Y, Y>0) return makeList(sigEnable( sigMul(lsig[0],lsig[1]), sigGT(lsig[1],sigReal(0.0)))); } else { // We gEnableFlag is false we replace enable by a simple multiplication return makeList(sigMul(lsig[0],lsig[1])); } } else if (p2 == &sigControl) { if (gGlobal->gEnableFlag) { // special case for sigEnable that requires a transformation // enable(X,Y) -> sigEnable(X*Y, Y>0) return makeList(sigEnable( lsig[0], lsig[1])); } else { // We gEnableFlag is false we replace control by identity function return makeList(lsig[0]); } } return makeList( p2(lsig[0],lsig[1]) ); } else if (isBoxPrim3(box, &p3)) { faustassert(lsig.size()==3); return makeList(p3(lsig[0],lsig[1],lsig[2])); } else if (isBoxPrim4(box, &p4)) { faustassert(lsig.size()==4); return makeList(p4(lsig[0],lsig[1],lsig[2],lsig[3])); } else if (isBoxPrim5(box, &p5)) { faustassert(lsig.size()==5); return makeList(p5(lsig[0],lsig[1],lsig[2],lsig[3],lsig[4])); } else if (isBoxFFun(box, ff)) { //cerr << "propagate en boxFFun of arity " << ffarity(ff) << endl; faustassert(int(lsig.size())==ffarity(ff)); return makeList(sigFFun(ff, listConvert(lsig))); } // User Interface Widgets else if (isBoxButton(box, label)) { faustassert(lsig.size()==0); return makeList(sigButton(normalizePath(cons(label, path)))); } else if (isBoxCheckbox(box, label)) { faustassert(lsig.size()==0); return makeList(sigCheckbox(normalizePath(cons(label, path)))); } else if (isBoxVSlider(box, label, cur, min, max, step)) { faustassert(lsig.size()==0); return makeList(sigVSlider(normalizePath(cons(label, path)), cur, min, max, step)); } else if (isBoxHSlider(box, label, cur, min, max, step)) { faustassert(lsig.size()==0); return makeList(sigHSlider(normalizePath(cons(label, path)), cur, min, max, step)); } else if (isBoxNumEntry(box, label, cur, min, max, step)) { faustassert(lsig.size()==0); return makeList(sigNumEntry(normalizePath(cons(label, path)), cur, min, max, step)); } else if (isBoxVBargraph(box, label, min, max)) { faustassert(lsig.size()==1); return makeList(sigVBargraph(normalizePath(cons(label, path)), min, max, lsig[0])); } else if (isBoxHBargraph(box, label, min, max)) { faustassert(lsig.size()==1); return makeList(sigHBargraph(normalizePath(cons(label, path)), min, max, lsig[0])); } else if (isBoxSoundfile(box, label, chan)) { faustassert(lsig.size()==1); Tree fullpath = normalizePath(cons(label, path)); Tree soundfile = sigSoundfile(fullpath); int c = tree2int(chan); siglist lsig2(c+3); lsig2[0] = sigSoundfileLength(soundfile); lsig2[1] = sigSoundfileRate(soundfile); lsig2[2] = sigSoundfileChannels(soundfile); // compute bound limited read index : int(max(0, min(ridx,length-1))) Tree ridx = sigIntCast(tree(gGlobal->gMaxPrim->symbol(), sigInt(0), tree(gGlobal->gMinPrim->symbol(), lsig[0], sigAdd(lsig2[0],sigInt(-1))))); for (int i = 0; i<c; i++) { lsig2[i+3] = sigSoundfileBuffer(soundfile, sigInt(i), ridx); } return lsig2; } // User Interface Groups else if (isBoxVGroup(box, label, t1)) { return propagate(slotenv,cons(cons(tree(0),label), path), t1, lsig); } else if (isBoxHGroup(box, label, t1)) { return propagate(slotenv, cons(cons(tree(1),label), path), t1, lsig); } else if (isBoxTGroup(box, label, t1)) { return propagate(slotenv, cons(cons(tree(2),label), path), t1, lsig); } // Block Diagram Composition Algebra else if (isBoxSeq(box, t1, t2)) { int in1, out1, in2, out2; getBoxType(t1, &in1, &out1); getBoxType(t2, &in2, &out2); faustassert(out1==in2); if (out1 == in2) { return propagate(slotenv, path, t2, propagate(slotenv, path,t1,lsig)); } else if (out1 > in2) { siglist lr = propagate(slotenv, path, t1,lsig); return listConcat(propagate(slotenv, path, t2, listRange(lr, 0, in2)), listRange(lr, in2, out1)); } else { return propagate(slotenv, path, t2, listConcat( propagate(slotenv, path, t1, listRange(lsig,0,in1)), listRange(lsig,in1,in1+in2-out1))); } } else if (isBoxPar(box, t1, t2)) { int in1, out1, in2, out2; getBoxType(t1, &in1, &out1); getBoxType(t2, &in2, &out2); return listConcat(propagate(slotenv, path, t1, listRange(lsig, 0, in1)), propagate(slotenv, path, t2, listRange(lsig, in1, in1+in2))); } else if (isBoxSplit(box, t1, t2)) { int in1, out1, in2, out2; getBoxType(t1, &in1, &out1); getBoxType(t2, &in2, &out2); siglist l1 = propagate(slotenv, path, t1, lsig); siglist l2 = split(l1, in2); return propagate(slotenv, path, t2, l2); } else if (isBoxMerge(box, t1, t2)) { int in1, out1, in2, out2; getBoxType(t1, &in1, &out1); getBoxType(t2, &in2, &out2); siglist l1 = propagate(slotenv, path, t1, lsig); siglist l2 = mix(l1, in2); return propagate(slotenv, path, t2, l2); } else if (isBoxRec(box, t1, t2)) { // Bug Corrected int in1, out1, in2, out2; getBoxType(t1, &in1, &out1); getBoxType(t2, &in2, &out2); Tree slotenv2 = lift(slotenv); // the environment must also be lifted siglist l0 = makeMemSigProjList(ref(1), in2); siglist l1 = propagate(slotenv2, path, t2, l0); siglist l2 = propagate(slotenv2, path, t1, listConcat(l1,listLift(lsig))); siglist l3 = (gGlobal->gFTZMode > 0) ? wrapWithFTZ(l2) : l2; Tree g = rec(listConvert(l3)); return makeSigProjList(g, out1); } stringstream error; error << "ERROR in file " << __FILE__ << ':' << __LINE__ << ", unrecognised box expression : " << boxpp(box) << endl; throw faustexception(error.str()); return siglist(); }
/** * Prepare a "pattern" by replacing variables x by special * pattern variables ?x. * * P[x] -> ?x * P[x(e)] -> x(P[e]) * P[e(f)] -> P[e](P[f]) * P[e:f] -> P[e]:P[f] * etc. */ static Tree preparePattern(Tree box) { // cerr << "preparePattern(" << boxpp(box) << ")" << endl; int id; double r; prim0 p0; prim1 p1; prim2 p2; prim3 p3; prim4 p4; prim5 p5; Tree t1, t2, t3, ff, label, cur, min, max, step, type, name, file, arg, body, fun, args, ldef, slot, ident, rules; xtended* xt = (xtended*) getUserData(box); // primitive elements if (xt) return box; else if (isBoxIdent(box)) return boxPatternVar(box); else if (isBoxAppl(box, fun, args)) { if (isBoxIdent(fun)) return boxAppl( fun, lmap(preparePattern,args)); else return boxAppl( preparePattern(fun), lmap(preparePattern,args)); } else if (isBoxAbstr(box,arg,body)) return box; else if (isBoxInt(box)) return box; else if (isBoxReal(box, &r)) return box; else if (isBoxWaveform(box)) return box; else if (isBoxCut(box)) return box; else if (isBoxWire(box)) return box; else if (isBoxPrim0(box, &p0)) return box; else if (isBoxPrim1(box, &p1)) return box; else if (isBoxPrim2(box, &p2)) return box; else if (isBoxPrim3(box, &p3)) return box; else if (isBoxPrim4(box, &p4)) return box; else if (isBoxPrim5(box, &p5)) return box; else if (isBoxWithLocalDef(box, body, ldef)) return boxWithLocalDef(preparePattern(body), ldef); // foreign elements else if (isBoxFFun(box, ff)) return box; else if (isBoxFConst(box, type, name, file)) return box; else if (isBoxFVar(box, type, name, file)) return box; // block diagram binary operator else if (isBoxSeq(box, t1, t2)) return boxSeq( preparePattern(t1), preparePattern(t2) ); else if (isBoxSplit(box, t1, t2)) return boxSplit( preparePattern(t1), preparePattern(t2) ); else if (isBoxMerge(box, t1, t2)) return boxMerge( preparePattern(t1), preparePattern(t2) ); else if (isBoxPar(box, t1, t2)) return boxPar( preparePattern(t1), preparePattern(t2) ); else if (isBoxRec(box, t1, t2)) return boxRec( preparePattern(t1), preparePattern(t2) ); // iterative block diagram construction else if (isBoxIPar(box, t1, t2, t3)) return boxIPar ( t1, t2, preparePattern(t3) ); else if (isBoxISeq(box, t1, t2, t3)) return boxISeq ( t1, t2, preparePattern(t3) ); else if (isBoxISum(box, t1, t2, t3)) return boxISum ( t1, t2, preparePattern(t3) ); else if (isBoxIProd(box, t1, t2, t3)) return boxIProd( t1, t2, preparePattern(t3) ); // static information else if (isBoxInputs(box, t1)) return boxInputs ( preparePattern(t1) ); else if (isBoxOutputs(box, t1)) return boxOutputs( preparePattern(t1) ); // user interface else if (isBoxButton(box, label)) return box; else if (isBoxCheckbox(box, label)) return box; else if (isBoxVSlider(box, label, cur, min, max, step)) return box; else if (isBoxHSlider(box, label, cur, min, max, step)) return box; else if (isBoxVGroup(box, label, t1)) return boxVGroup(label, preparePattern(t1)); else if (isBoxHGroup(box, label, t1)) return boxHGroup(label, preparePattern(t1)); else if (isBoxTGroup(box, label, t1)) return boxTGroup(label, preparePattern(t1)); else if (isBoxHBargraph(box, label, min, max)) return box; else if (isBoxVBargraph(box, label, min, max)) return box; else if (isBoxNumEntry(box, label, cur, min, max, step)) return box; else if (isNil(box)) return box; else if (isList(box)) return lmap(preparePattern, box); else if (isBoxEnvironment(box)) return box; /* not expected else if (isClosure(box, abstr, genv, vis, lenv)) { fout << "closure[" << boxpp(abstr) << ", genv = " << envpp(genv) << ", lenv = " << envpp(lenv) << "]"; } */ else if (isBoxComponent(box, label)) return box; else if (isBoxAccess(box, t1, t2)) return box; /* not expected else if (isImportFile(box, label)) { fout << "import(" << tree2str(label) << ')'; } */ else if (isBoxSlot(box, &id)) return box; else if (isBoxSymbolic(box, slot, body)) return box; // Pattern Matching Extensions else if (isBoxCase(box, rules)) return box; else if (isBoxPatternVar(box, ident)) return box; // None of the previous tests succeded, then it is not a valid box else { stringstream error; error << "ERROR in preparePattern() : " << *box << " is not a valid box" << endl; throw faustexception(error.str()); } return box; }
/** * Apply a function to a list of arguments. * Apply a function F to a list of arguments (a,b,c,...). * F can be either a closure over an abstraction, or a * pattern matcher. If it is not the case then we have : * F(a,b,c,...) ==> (a,b,c,...):F * * @param fun the function to apply * @param larg the list of arguments * @return the resulting expression in normal form */ static Tree applyList (Tree fun, Tree larg) { Tree abstr; Tree globalDefEnv; Tree visited; Tree localValEnv; Tree envList; Tree originalRules; Tree revParamList; Tree id; Tree body; Automaton* automat; int state; prim2 p2; //cerr << "applyList (" << *fun << ", " << *larg << ")" << endl; if (isNil(larg)) return fun; if (isBoxError(fun) || isBoxError(larg)) { return boxError(); } if (isBoxPatternMatcher(fun, automat, state, envList, originalRules, revParamList)) { Tree result; int state2; vector<Tree> envVect; list2vec(envList, envVect); //cerr << "applyList/apply_pattern_matcher(" << automat << "," << state << "," << *hd(larg) << ")" << endl; state2 = apply_pattern_matcher(automat, state, hd(larg), result, envVect); //cerr << "state2 = " << state2 << "; result = " << *result << endl; if (state2 >= 0 && isNil(result)) { // we need to continue the pattern matching return applyList( boxPatternMatcher(automat, state2, vec2list(envVect), originalRules, cons(hd(larg),revParamList)), tl(larg) ); } else if (state2 < 0) { stringstream error; error << "ERROR : pattern matching failed, no rule of " << boxpp(boxCase(originalRules)) << " matches argument list " << boxpp(reverse(cons(hd(larg), revParamList))) << endl; throw faustexception(error.str()); } else { // Pattern Matching was succesful // the result is a closure that we need to evaluate. if (isClosure(result, body, globalDefEnv, visited, localValEnv)) { // why ??? return simplifyPattern(eval(body, nil, localValEnv)); //return eval(body, nil, localValEnv); return applyList(eval(body, gGlobal->nil, localValEnv), tl(larg)); } else { cerr << "wrong result from pattern matching (not a closure) : " << boxpp(result) << endl; return boxError(); } } } if (!isClosure(fun, abstr, globalDefEnv, visited, localValEnv)) { // principle : f(a,b,c,...) ==> (a,b,c,...):f int ins, outs; // check arity of function Tree efun = a2sb(fun); //cerr << "TRACEPOINT 1 : " << boxpp(efun) << endl; if (!getBoxType(efun, &ins, &outs)) { // on laisse comme ca pour le moment // we can't determine the input arity of the expression // hope for the best return boxSeq(larg2par(larg), fun); } // check arity of arg list if (!boxlistOutputs(larg, &outs)) { // we don't know yet the output arity of larg. Therefore we can't // do any arity checking nor add _ to reach the required number of arguments // cerr << "warning : can't infere the type of : " << boxpp(larg) << endl; return boxSeq(larg2par(larg), fun); } if (outs > ins) { stringstream error; error << "too much arguments : " << outs << ", instead of : " << ins << endl; error << "when applying : " << boxpp(fun) << endl << "to : " << boxpp(larg) << endl; throw faustexception(error.str()); } if ((outs == 1) && (( isBoxPrim2(fun, &p2) && (p2 != sigPrefix)) || (getUserData(fun) && ((xtended*)getUserData(fun))->isSpecialInfix()))) { // special case : /(3) ==> _,3 : / Tree larg2 = concat(nwires(ins-outs), larg); return boxSeq(larg2par(larg2), fun); } else { Tree larg2 = concat(larg, nwires(ins-outs)); return boxSeq(larg2par(larg2), fun); } } if (isBoxEnvironment(abstr)) { evalerrorbox(yyfilename, -1, "an environment can't be used as a function", fun); } if (!isBoxAbstr(abstr, id, body)) { evalerror(yyfilename, -1, "(internal) not an abstraction inside closure", fun); } // try to synthetise a name from the function name and the argument name { Tree arg = eval(hd(larg), visited, localValEnv); Tree narg; if ( isBoxNumeric(arg,narg) ) { arg = narg; } Tree f = eval(body, visited, pushValueDef(id, arg, localValEnv)); Tree fname; if (getDefNameProperty(fun, fname)) { stringstream s; s << tree2str(fname); if (!gGlobal->gSimpleNames) s << "(" << boxpp(arg) << ")"; setDefNameProperty(f, s.str()); } return applyList(f, tl(larg)); } }
/** * evallabel replace "...%2i..." occurences in label with value of i */ static const char * evalLabel (const char* src, Tree visited, Tree localValEnv) { //std::cerr << "Eval Label : " << src; int state = 0; // current state std::string dst; // label once evaluated std::string ident; // current identifier std::string format; // current format while (state != -1) { char c = *src++; if (state == 0) { if (c == 0) { state = -1; } else if (c == '%') { ident = ""; format = ""; state = 1; } else { dst+=c; state = 0; } } else if (state == 1) { if (c == 0) { // fin et pas d'indentifiant, abandon dst += '%'; dst += format; state = -1; } else if (isDigitChar(c)) { format += c; state = 1; } else if (isIdentChar(c)) { ident += c; state = 2; } else { // caractere de ponctuation et pas d'indentifiant, abandon dst += '%'; dst += format; src--; state = 0; } } else if (state == 2) { if (isIdentChar(c)) { ident += c; state = 2; } else { writeIdentValue(dst, format, ident, visited, localValEnv); src--; state = 0; } } else { stringstream error; error << "internal error in evallabel : undefined state " << state << std::endl; throw faustexception(error.str()); } } const char* val = strdup(dst.c_str()); //std::cerr << " ===> " << val << std::endl; return val; }
static Tree realeval (Tree exp, Tree visited, Tree localValEnv) { //Tree def; Tree fun; Tree arg; Tree var, num, body, ldef; Tree label; Tree cur, lo, hi, step; Tree e1, e2, exp2, notused, visited2, lenv2; Tree rules; Tree id; //cerr << "EVAL " << *exp << " (visited : " << *visited << ")" << endl; //cerr << "REALEVAL of " << *exp << endl; xtended* xt = (xtended*) getUserData(exp); // constants //----------- if ( xt || isBoxInt(exp) || isBoxReal(exp) || isBoxWire(exp) || isBoxCut(exp) || isBoxPrim0(exp) || isBoxPrim1(exp) || isBoxPrim2(exp) || isBoxPrim3(exp) || isBoxPrim4(exp) || isBoxPrim5(exp) || isBoxFFun(exp) || isBoxFConst(exp) || isBoxFVar(exp) || isBoxWaveform(exp)) { return exp; // block-diagram constructors //--------------------------- } else if (isBoxSeq(exp, e1, e2)) { return boxSeq(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); } else if (isBoxPar(exp, e1, e2)) { return boxPar(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); } else if (isBoxRec(exp, e1, e2)) { return boxRec(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); } else if (isBoxSplit(exp, e1, e2)) { return boxSplit(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); } else if (isBoxMerge(exp, e1, e2)) { return boxMerge(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); // Modules //-------- } else if (isBoxAccess(exp, body, var)) { Tree val = eval(body, visited, localValEnv); if (isClosure(val, exp2, notused, visited2, lenv2)) { // it is a closure, we have an environment to access return eval(closure(var,notused,visited2,lenv2), visited, localValEnv); } else { evalerror(getDefFileProp(exp), getDefLineProp(exp), "no environment to access", exp); } //////////////////////en chantier//////////////////////////// } else if (isBoxModifLocalDef(exp, body, ldef)) { Tree val = eval(body, visited, localValEnv); if (isClosure(val, exp2, notused, visited2, lenv2)) { // we rebuild the closure using a copy of the original environment // modified with some new definitions Tree lenv3 = copyEnvReplaceDefs(lenv2, ldef, visited2, localValEnv); return eval(closure(exp2,notused,visited2,lenv3), visited, localValEnv); } else { evalerror(getDefFileProp(exp), getDefLineProp(exp), "not a closure", val); evalerror(getDefFileProp(exp), getDefLineProp(exp), "no environment to access", exp); } /////////////////////////////////////////////////////////////////// } else if (isBoxComponent(exp, label)) { string fname = tree2str(label); Tree eqlst = gGlobal->gReader.expandlist(gGlobal->gReader.getlist(fname)); Tree res = closure(boxIdent("process"), gGlobal->nil, gGlobal->nil, pushMultiClosureDefs(eqlst, gGlobal->nil, gGlobal->nil)); setDefNameProperty(res, label); //cerr << "component is " << boxpp(res) << endl; return res; } else if (isBoxLibrary(exp, label)) { string fname = tree2str(label); Tree eqlst = gGlobal->gReader.expandlist(gGlobal->gReader.getlist(fname)); Tree res = closure(boxEnvironment(), gGlobal->nil, gGlobal->nil, pushMultiClosureDefs(eqlst, gGlobal->nil, gGlobal->nil)); setDefNameProperty(res, label); //cerr << "component is " << boxpp(res) << endl; return res; // user interface elements //------------------------ } else if (isBoxButton(exp, label)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); //cout << "button label : " << l1 << " become " << l2 << endl; return ((l1 == l2) ? exp : boxButton(tree(l2))); } else if (isBoxCheckbox(exp, label)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); //cout << "check box label : " << l1 << " become " << l2 << endl; return ((l1 == l2) ? exp : boxCheckbox(tree(l2))); } else if (isBoxVSlider(exp, label, cur, lo, hi, step)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return ( boxVSlider(tree(l2), tree(eval2double(cur, visited, localValEnv)), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv)), tree(eval2double(step, visited, localValEnv)))); } else if (isBoxHSlider(exp, label, cur, lo, hi, step)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return ( boxHSlider(tree(l2), tree(eval2double(cur, visited, localValEnv)), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv)), tree(eval2double(step, visited, localValEnv)))); } else if (isBoxNumEntry(exp, label, cur, lo, hi, step)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return (boxNumEntry(tree(l2), tree(eval2double(cur, visited, localValEnv)), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv)), tree(eval2double(step, visited, localValEnv)))); } else if (isBoxVGroup(exp, label, arg)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxVGroup(tree(l2), eval(arg, visited, localValEnv) ); } else if (isBoxHGroup(exp, label, arg)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxHGroup(tree(l2), eval(arg, visited, localValEnv) ); } else if (isBoxTGroup(exp, label, arg)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxTGroup(tree(l2), eval(arg, visited, localValEnv) ); } else if (isBoxHBargraph(exp, label, lo, hi)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxHBargraph(tree(l2), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv))); } else if (isBoxVBargraph(exp, label, lo, hi)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxVBargraph(tree(l2), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv))); // lambda calculus //---------------- } else if (isBoxIdent(exp)) { return evalIdDef(exp, visited, localValEnv); } else if (isBoxWithLocalDef(exp, body, ldef)) { return eval(body, visited, pushMultiClosureDefs(ldef, visited, localValEnv)); } else if (isBoxAppl(exp, fun, arg)) { return applyList( eval(fun, visited, localValEnv), revEvalList(arg, visited, localValEnv) ); } else if (isBoxAbstr(exp)) { // it is an abstraction : return a closure return closure(exp, gGlobal->nil, visited, localValEnv); } else if (isBoxEnvironment(exp)) { // environment : return also a closure return closure(exp, gGlobal->nil, visited, localValEnv); } else if (isClosure(exp, exp2, notused, visited2, lenv2)) { if (isBoxAbstr(exp2)) { // a 'real' closure return closure(exp2, gGlobal->nil, setUnion(visited,visited2), lenv2); } else if (isBoxEnvironment(exp2)) { // a 'real' closure return closure(exp2, gGlobal->nil, setUnion(visited,visited2), lenv2); } else { // it was a suspended evaluation return eval(exp2, setUnion(visited,visited2), lenv2); } // Algorithmic constructions //-------------------------- } else if (isBoxIPar(exp, var, num, body)) { int n = eval2int(num, visited, localValEnv); return iteratePar(var, n, body, visited, localValEnv); } else if (isBoxISeq(exp, var, num, body)) { int n = eval2int(num, visited, localValEnv); return iterateSeq(var, n, body, visited, localValEnv); } else if (isBoxISum(exp, var, num, body)) { int n = eval2int(num, visited, localValEnv); return iterateSum(var, n, body, visited, localValEnv); } else if (isBoxIProd(exp, var, num, body)) { int n = eval2int(num, visited, localValEnv); return iterateProd(var, n, body, visited, localValEnv); // static } else if (isBoxInputs(exp, body)) { int ins, outs; Tree b = a2sb(eval(body, visited, localValEnv)); if (getBoxType (b, &ins, &outs)) { return boxInt(ins); } else { stringstream error; error << "ERROR : can't evaluate ' : " << *exp << endl; throw faustexception(error.str()); } } else if (isBoxOutputs(exp, body)) { int ins, outs; Tree b = a2sb(eval(body, visited, localValEnv)); if (getBoxType (b, &ins, &outs)) { return boxInt(outs); } else { stringstream error; error << "ERROR : can't evaluate ' : " << *exp << endl; throw faustexception(error.str()); } } else if (isBoxSlot(exp)) { return exp; } else if (isBoxSymbolic(exp)) { return exp; // Pattern matching extension //--------------------------- } else if (isBoxCase(exp, rules)) { return evalCase(rules, localValEnv); } else if (isBoxPatternVar(exp, id)) { return exp; //return evalIdDef(id, visited, localValEnv); } else if (isBoxPatternMatcher(exp)) { return exp; } else { stringstream error; error << "ERROR : EVAL doesn't intercept : " << *exp << endl; throw faustexception(error.str()); } return NULL; }
/** * Simplify inside a block-diagram : S[A*B] => S[A]*S[B] */ Tree insideBoxSimplification (Tree box) { int i; double r; prim0 p0; prim1 p1; prim2 p2; prim3 p3; prim4 p4; prim5 p5; Tree t1, t2, ff, label, cur, min, max, step, type, name, file, slot, body; xtended* xt = (xtended*)getUserData(box); // Extended Primitives if (xt) { return box; } // Numbers and Constants else if (isBoxInt(box, &i)) { return box; } else if (isBoxReal(box, &r)) { return box; } else if (isBoxFConst(box, type, name, file)) { return box; } else if (isBoxFVar(box, type, name, file)) { return box; } // Wire and Cut else if (isBoxCut(box)) { return box; } else if (isBoxWire(box)) { return box; } // Primitives else if (isBoxPrim0(box, &p0)) { return box; } else if (isBoxPrim1(box, &p1)) { return box; } else if (isBoxPrim2(box, &p2)) { return box; } else if (isBoxPrim3(box, &p3)) { return box; } else if (isBoxPrim4(box, &p4)) { return box; } else if (isBoxPrim5(box, &p5)) { return box; } else if (isBoxFFun(box, ff)) { return box; } // User Interface Widgets else if (isBoxButton(box, label)) { return box; } else if (isBoxCheckbox(box, label)) { return box; } else if (isBoxVSlider(box, label, cur, min, max, step)) { return box; } else if (isBoxHSlider(box, label, cur, min, max, step)) { return box; } else if (isBoxNumEntry(box, label, cur, min, max, step)) { return box; } else if (isBoxVBargraph(box, label, min, max)) { return box; } else if (isBoxHBargraph(box, label, min, max)) { return box; } // User Interface Groups else if (isBoxVGroup(box, label, t1)) { return boxVGroup(label, boxSimplification(t1)); } else if (isBoxHGroup(box, label, t1)) { return boxHGroup(label, boxSimplification(t1)); } else if (isBoxTGroup(box, label, t1)) { return boxTGroup(label, boxSimplification(t1)); } // Slots and Symbolic Boxes else if (isBoxSlot(box)) { return box;; } else if (isBoxSymbolic(box, slot, body)){ Tree b = boxSimplification(body); return boxSymbolic(slot,b); } // Block Diagram Composition Algebra else if (isBoxSeq(box, t1, t2)) { Tree s1 = boxSimplification(t1); Tree s2 = boxSimplification(t2); return boxSeq(s1,s2); } else if (isBoxPar(box, t1, t2)) { Tree s1 = boxSimplification(t1); Tree s2 = boxSimplification(t2); return boxPar(s1,s2); } else if (isBoxSplit(box, t1, t2)) { Tree s1 = boxSimplification(t1); Tree s2 = boxSimplification(t2); return boxSplit(s1,s2); } else if (isBoxMerge(box, t1, t2)) { Tree s1 = boxSimplification(t1); Tree s2 = boxSimplification(t2); return boxMerge(s1,s2); } else if (isBoxRec(box, t1, t2)) { Tree s1 = boxSimplification(t1); Tree s2 = boxSimplification(t2); return boxRec(s1,s2); } stringstream error; error << "ERROR in file " << __FILE__ << ':' << __LINE__ << ", unrecognised box expression : " << *box << endl; throw faustexception(error.str()); return 0; }