FAUST compiler  0.9.9.6b8
eval.cpp
Go to the documentation of this file.
00001 /************************************************************************
00002  ************************************************************************
00003     FAUST compiler
00004     Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
00005     ---------------------------------------------------------------------
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  ************************************************************************
00020  ************************************************************************/
00021  #define TRACE
00022 
00032 #include "eval.hh"
00033 #include <stdio.h>
00034 #include "errormsg.hh"
00035 #include "ppbox.hh"
00036 #include "simplify.hh"
00037 #include "propagate.hh"
00038 #include "patternmatcher.hh"
00039 #include "signals.hh"
00040 #include "xtended.hh"
00041 #include "loopDetector.hh"
00042 #include "property.hh"
00043 #include "names.hh"
00044 #include "compatibility.hh"
00045 
00046 
00047 #include <assert.h>
00048 extern SourceReader gReader;
00049 extern int  gMaxNameSize;
00050 extern bool gSimpleNames;
00051 extern bool gSimplifyDiagrams;
00052 // History
00053 // 23/05/2005 : New environment management
00054 
00055 
00056 //-------------- prototypes ---------------------------------------------------------
00057 static Tree     a2sb(Tree exp);
00058 static Tree     eval (Tree exp, Tree visited, Tree localValEnv);
00059 static Tree     realeval (Tree exp, Tree visited, Tree localValEnv);
00060 static Tree     revEvalList (Tree lexp, Tree visited, Tree localValEnv);
00061 static Tree     applyList (Tree fun, Tree larg);
00062 static Tree     iteratePar (Tree var, int num, Tree body, Tree visited, Tree localValEnv);
00063 static Tree     iterateSeq (Tree id, int num, Tree body, Tree visited, Tree localValEnv);
00064 static Tree     iterateSum (Tree id, int num, Tree body, Tree visited, Tree localValEnv);
00065 static Tree     iterateProd (Tree id, int num, Tree body, Tree visited, Tree localValEnv);
00066 static Tree     larg2par (Tree larg);
00067 static int      eval2int (Tree exp, Tree visited, Tree localValEnv);
00068 static double   eval2double (Tree exp, Tree visited, Tree localValEnv);
00069 static const char * evalLabel (const char* l, Tree visited, Tree localValEnv);
00070 
00071 static Tree     evalIdDef(Tree id, Tree visited, Tree env);
00072 
00073 
00074 
00075 static Tree     evalCase(Tree rules, Tree env);
00076 static Tree     evalRuleList(Tree rules, Tree env);
00077 static Tree     evalRule(Tree rule, Tree env);
00078 static Tree     evalPatternList(Tree patterns, Tree env);
00079 static Tree     evalPattern(Tree pattern, Tree env);
00080 
00081 static Tree     patternSimplification (Tree pattern);
00082 static bool     isBoxNumeric (Tree in, Tree& out);
00083 
00084 static Tree     vec2list(const vector<Tree>& v);
00085 static void     list2vec(Tree l, vector<Tree>& v);
00086 static Tree     listn (int n, Tree e);
00087 
00088 static Tree     boxSimplification(Tree box);
00089 
00090 // Public Interface
00091 //----------------------
00092 
00093 
00101 Tree evalprocess (Tree eqlist)
00102 {
00103     Tree b = a2sb(eval(boxIdent("process"), nil, pushMultiClosureDefs(eqlist, nil, nil)));
00104 
00105     if (gSimplifyDiagrams) {
00106         b = boxSimplification(b);
00107     }
00108 
00109     return b;
00110 }
00111 
00112 
00113 /* Eval a documentation expression. */
00114 
00115 Tree evaldocexpr (Tree docexpr, Tree eqlist)
00116 {
00117     return a2sb(eval(docexpr, nil, pushMultiClosureDefs(eqlist, nil, nil)));
00118 }
00119 
00120 
00121 
00122 // Private Implementation
00123 //------------------------
00124 
00132 property<Tree> gSymbolicBoxProperty;
00133 
00134 static Tree real_a2sb(Tree exp);
00135 
00136 static Tree a2sb(Tree exp)
00137 {
00138     Tree    result;
00139     Tree    id;
00140 
00141     if (gSymbolicBoxProperty.get(exp, result)) {
00142         return result;
00143     }
00144 
00145     result = real_a2sb(exp);
00146     if (result != exp && getDefNameProperty(exp, id)) {
00147         setDefNameProperty(result, id);     // propagate definition name property when needed
00148     }
00149     gSymbolicBoxProperty.set(exp, result);
00150     return result;
00151 }
00152 
00153 static int  gBoxSlotNumber = 0;     
00154 
00155 static Tree real_a2sb(Tree exp)
00156 {
00157     Tree abstr, visited, unusedEnv, localValEnv, var, name, body;
00158 
00159     if (isClosure(exp, abstr, unusedEnv, visited, localValEnv)) {
00160 
00161         if (isBoxIdent(abstr)) {
00162             // special case introduced with access and components
00163             Tree result = a2sb(eval(abstr, visited, localValEnv));
00164 
00165             // propagate definition name property when needed
00166             if (getDefNameProperty(exp, name))  setDefNameProperty(result, name);
00167             return result;
00168 
00169         } else if (isBoxAbstr(abstr, var, body)) {
00170             // Here we have remaining abstraction that we will try to 
00171             // transform in a symbolic box by applying it to a slot
00172 
00173             Tree slot = boxSlot(++gBoxSlotNumber); 
00174             stringstream s; s << boxpp(var);
00175             setDefNameProperty(slot, s.str() ); // ajout YO
00176             
00177             // Apply the abstraction to the slot
00178             Tree result = boxSymbolic(slot, a2sb(eval(body, visited, pushValueDef(var, slot, localValEnv))));
00179 
00180             // propagate definition name property when needed
00181             if (getDefNameProperty(exp, name)) setDefNameProperty(result, name);
00182             return result;
00183 
00184         } else if (isBoxEnvironment(abstr)) {
00185             return abstr;
00186     
00187         } else {
00188             evalerror(yyfilename, -1, " a2sb : internal error : not an abstraction inside closure ", exp);
00189             exit(1);
00190         }
00191         
00192     } else if (isBoxPatternMatcher(exp)) {
00193         // Here we have remaining PM rules that we will try to 
00194         // transform in a symbolic box by applying it to a slot
00195         
00196         Tree slot = boxSlot(++gBoxSlotNumber);          
00197         stringstream s; s << "PM" << gBoxSlotNumber;
00198         setDefNameProperty(slot, s.str() ); 
00199         
00200         // apply the PM rules to the slot and transfoms the result in a symbolic box
00201         Tree result = boxSymbolic(slot, a2sb(applyList(exp, cons(slot,nil))));
00202 
00203         // propagate definition name property when needed
00204         if (getDefNameProperty(exp, name)) setDefNameProperty(result, name);
00205         return result;
00206 
00207     } else {
00208         // it is a constructor : transform each branches
00209         unsigned int    ar = exp->arity();
00210         tvec            B(ar);
00211         bool            modified = false;
00212         for (unsigned int i = 0; i < ar; i++) {
00213             Tree b = exp->branch(i);
00214             Tree m = a2sb(b);
00215             B[i] = m;
00216             if (b != m) modified=true;
00217         }
00218         Tree r = (modified) ? CTree::make(exp->node(), B) : exp;
00219         return r;
00220     }
00221 }
00222 
00223 static bool autoName(Tree exp , Tree& id)
00224 {
00225     stringstream s; s << boxpp(exp);
00226     id = tree(s.str().c_str());
00227     return true;
00228 }
00229 
00230 bool getArgName(Tree t, Tree& id)
00231 {
00232     //return getDefNameProperty(t, id) || autoName(t, id) ;
00233     return autoName(t, id) ;
00234 }
00235 
00236 
00237 
00247 static loopDetector LD(1024, 1);
00248 
00249 
00250 static Node EVALPROPERTY(symbol("EvalProperty"));
00251 
00258 void setEvalProperty(Tree box, Tree env, Tree value)
00259 {
00260     setProperty(box, tree(EVALPROPERTY,env), value);
00261 }
00262 
00263 
00271 bool getEvalProperty(Tree box, Tree env, Tree& value)
00272 {
00273     return getProperty(box, tree(EVALPROPERTY,env), value);
00274 }
00275 
00276 
00277 static Tree eval (Tree exp, Tree visited, Tree localValEnv)
00278 {
00279     Tree    id;
00280     Tree    result;
00281     
00282     LD.detect(cons(exp,localValEnv));
00283     
00284     if (!getEvalProperty(exp, localValEnv, result)) {
00285         //cerr << "ENTER eval("<< *exp << ") with env " << *localValEnv << endl;
00286         result = realeval(exp, visited, localValEnv);
00287         setEvalProperty(exp, localValEnv, result);
00288         //cerr << "EXIT eval(" << *exp << ") IS " << *result << " with env " << *localValEnv << endl;
00289         if (getDefNameProperty(exp, id)) {
00290             setDefNameProperty(result, id);     // propagate definition name property 
00291         }
00292     }
00293     return result;
00294 }
00295 
00306 static Tree realeval (Tree exp, Tree visited, Tree localValEnv)
00307 {
00308     //Tree  def;
00309     Tree    fun;
00310     Tree    arg;
00311     Tree    var, num, body, ldef;
00312     Tree    label;
00313     Tree    cur, lo, hi, step;
00314     Tree    e1, e2, exp2, notused, visited2, lenv2;
00315     Tree    rules;
00316     Tree    id;
00317 
00318     //cerr << "EVAL " << *exp << " (visited : " << *visited << ")" << endl;
00319     //cerr << "REALEVAL of " << *exp << endl;
00320     
00321     xtended* xt = (xtended*) getUserData(exp);
00322 
00323 
00324     // constants
00325     //-----------
00326     
00327     if (    xt || 
00328             isBoxInt(exp) || isBoxReal(exp) || 
00329             isBoxWire(exp) || isBoxCut(exp) ||
00330             isBoxPrim0(exp) || isBoxPrim1(exp) || 
00331             isBoxPrim2(exp) || isBoxPrim3(exp) || 
00332             isBoxPrim4(exp) || isBoxPrim5(exp) ||
00333             isBoxFFun(exp) || isBoxFConst(exp) || isBoxFVar(exp) ) {
00334         return exp;
00335 
00336     // block-diagram constructors
00337     //---------------------------
00338     
00339     } else if ( isBoxSeq(exp, e1, e2) ) {
00340         return boxSeq(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00341 
00342     } else if ( isBoxPar(exp, e1, e2) ) {
00343         return boxPar(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00344 
00345     } else if ( isBoxRec(exp, e1, e2) ) {
00346         return boxRec(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00347 
00348     } else if ( isBoxSplit(exp, e1, e2) ) {
00349         return boxSplit(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00350 
00351     } else if ( isBoxMerge(exp, e1, e2) ) {
00352         return boxMerge(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00353         
00354     // Modules
00355     //--------
00356 
00357     } else if (isBoxAccess(exp, body, var)) {
00358         Tree val = eval(body, visited, localValEnv);
00359         if (isClosure(val, exp2, notused, visited2, lenv2)) {
00360             // it is a closure, we have an environment to access
00361             return eval(closure(var,notused,visited2,lenv2), visited, localValEnv);
00362         } else {
00363             evalerror(getDefFileProp(exp), getDefLineProp(exp), "No environment to access ", exp);
00364             exit(1);
00365         }
00366 
00368 
00369     } else if (isBoxModifLocalDef(exp, body, ldef)) {
00370         Tree val = eval(body, visited, localValEnv);
00371         if (isClosure(val, exp2, notused, visited2, lenv2)) {
00372             // we rebuild the closure using a copy of the original environment
00373             // modified with some new definitions
00374             Tree lenv3 = copyEnvReplaceDefs(lenv2, ldef, visited2, localValEnv);
00375             return eval(closure(exp2,notused,visited2,lenv3), visited, localValEnv);
00376         } else {
00377 
00378             evalerror(getDefFileProp(exp), getDefLineProp(exp), "not a closure ", val);
00379             evalerror(getDefFileProp(exp), getDefLineProp(exp), "No environment to access ", exp);
00380             exit(1);
00381         }
00382 
00384 
00385     } else if (isBoxComponent(exp, label)) {
00386         string  fname   = tree2str(label);
00387         Tree    eqlst   = gReader.expandlist(gReader.getlist(fname));
00388         Tree    res     = closure(boxIdent("process"), nil, nil, pushMultiClosureDefs(eqlst, nil, nil));
00389         setDefNameProperty(res, label);
00390         //cerr << "component is " << boxpp(res) << endl;
00391         return res;
00392 
00393     } else if (isBoxLibrary(exp, label)) {
00394         string  fname   = tree2str(label);
00395         Tree    eqlst   = gReader.expandlist(gReader.getlist(fname));
00396         Tree    res     = closure(boxEnvironment(), nil, nil, pushMultiClosureDefs(eqlst, nil, nil));
00397         setDefNameProperty(res, label);
00398         //cerr << "component is " << boxpp(res) << endl;
00399         return res;
00400 
00401 
00402     // user interface elements
00403     //------------------------
00404     
00405     } else if (isBoxButton(exp, label)) {
00406         const char* l1 = tree2str(label);
00407         const char* l2= evalLabel(l1, visited, localValEnv);
00408         //cout << "button label : " << l1 << " become " << l2 << endl;
00409         return ((l1 == l2) ? exp : boxButton(tree(l2)));
00410 
00411     } else if (isBoxCheckbox(exp, label)) {
00412         const char* l1 = tree2str(label);
00413         const char* l2= evalLabel(l1, visited, localValEnv);
00414         //cout << "check box label : " << l1 << " become " << l2 << endl;
00415         return ((l1 == l2) ? exp : boxCheckbox(tree(l2)));
00416 
00417     } else if (isBoxVSlider(exp, label, cur, lo, hi, step)) {
00418         const char* l1 = tree2str(label);
00419         const char* l2= evalLabel(l1, visited, localValEnv);
00420         return ( boxVSlider(tree(l2),
00421                     tree(eval2double(cur, visited, localValEnv)),
00422                     tree(eval2double(lo, visited, localValEnv)),
00423                     tree(eval2double(hi, visited, localValEnv)),
00424                     tree(eval2double(step, visited, localValEnv))));
00425 
00426     } else if (isBoxHSlider(exp, label, cur, lo, hi, step)) {
00427         const char* l1 = tree2str(label);
00428         const char* l2= evalLabel(l1, visited, localValEnv);
00429         return ( boxHSlider(tree(l2),
00430                     tree(eval2double(cur, visited, localValEnv)),
00431                     tree(eval2double(lo, visited, localValEnv)),
00432                     tree(eval2double(hi, visited, localValEnv)),
00433                     tree(eval2double(step, visited, localValEnv))));
00434 
00435     } else if (isBoxNumEntry(exp, label, cur, lo, hi, step)) {
00436         const char* l1 = tree2str(label);
00437         const char* l2= evalLabel(l1, visited, localValEnv);
00438         return (boxNumEntry(tree(l2),
00439                     tree(eval2double(cur, visited, localValEnv)),
00440                     tree(eval2double(lo, visited, localValEnv)),
00441                     tree(eval2double(hi, visited, localValEnv)),
00442                     tree(eval2double(step, visited, localValEnv))));
00443 
00444     } else if (isBoxVGroup(exp, label, arg)) {
00445         const char* l1 = tree2str(label);
00446         const char* l2= evalLabel(l1, visited, localValEnv);
00447         return boxVGroup(tree(l2),  eval(arg, visited, localValEnv) );
00448 
00449     } else if (isBoxHGroup(exp, label, arg)) {
00450         const char* l1 = tree2str(label);
00451         const char* l2= evalLabel(l1, visited, localValEnv);
00452         return boxHGroup(tree(l2),  eval(arg, visited, localValEnv) );
00453 
00454     } else if (isBoxTGroup(exp, label, arg)) {
00455         const char* l1 = tree2str(label);
00456         const char* l2= evalLabel(l1, visited, localValEnv);
00457         return boxTGroup(tree(l2),  eval(arg, visited, localValEnv) );
00458 
00459     } else if (isBoxHBargraph(exp, label, lo, hi)) {
00460         const char* l1 = tree2str(label);
00461         const char* l2= evalLabel(l1, visited, localValEnv);
00462         return boxHBargraph(tree(l2),
00463                     tree(eval2double(lo, visited, localValEnv)),
00464                     tree(eval2double(hi, visited, localValEnv)));
00465 
00466     } else if (isBoxVBargraph(exp, label, lo, hi)) {
00467         const char* l1 = tree2str(label);
00468         const char* l2= evalLabel(l1, visited, localValEnv);
00469         return boxVBargraph(tree(l2),
00470                     tree(eval2double(lo, visited, localValEnv)),
00471                     tree(eval2double(hi, visited, localValEnv)));
00472 
00473     // lambda calculus
00474     //----------------
00475         
00476     } else if (isBoxIdent(exp)) {
00477         return evalIdDef(exp, visited, localValEnv);
00478 
00479     } else if (isBoxWithLocalDef(exp, body, ldef)) {
00480         return eval(body, visited, pushMultiClosureDefs(ldef, visited, localValEnv));
00481     
00482     } else if (isBoxAppl(exp, fun, arg)) {
00483         return applyList( eval(fun, visited, localValEnv),
00484                           revEvalList(arg, visited, localValEnv) );
00485 
00486     } else if (isBoxAbstr(exp)) {
00487         // it is an abstraction : return a closure
00488         return closure(exp, nil, visited, localValEnv);
00489 
00490     } else if (isBoxEnvironment(exp)) {
00491         // environment : return also a closure
00492         return closure(exp, nil, visited, localValEnv);
00493 
00494     } else if (isClosure(exp, exp2, notused, visited2, lenv2)) {
00495 
00496         if (isBoxAbstr(exp2)) {
00497             // a 'real' closure
00498             return closure(exp2, nil, setUnion(visited,visited2), lenv2);
00499         } else if (isBoxEnvironment(exp2)) {
00500             // a 'real' closure
00501             return closure(exp2, nil, setUnion(visited,visited2), lenv2);
00502         } else {
00503             // it was a suspended evaluation
00504             return eval(exp2, setUnion(visited,visited2), lenv2);
00505         }
00506 
00507     // Algorithmic constructions
00508     //--------------------------
00509     
00510     } else if (isBoxIPar(exp, var, num, body)) {
00511         int n = eval2int(num, visited, localValEnv);
00512         return iteratePar(var, n, body, visited, localValEnv);
00513 
00514     } else if (isBoxISeq(exp, var, num, body)) {
00515         int n = eval2int(num, visited, localValEnv);
00516         return iterateSeq(var, n, body, visited, localValEnv);
00517 
00518     } else if (isBoxISum(exp, var, num, body)) {
00519         int n = eval2int(num, visited, localValEnv);
00520         return iterateSum(var, n, body, visited, localValEnv);
00521 
00522     } else if (isBoxIProd(exp, var, num, body)) {
00523         int n = eval2int(num, visited, localValEnv);
00524         return iterateProd(var, n, body, visited, localValEnv);
00525         
00526     } else if (isBoxSlot(exp))      { 
00527         return exp; 
00528     
00529     } else if (isBoxSymbolic(exp))  {
00530      
00531         return exp;
00532     
00533 
00534     // Pattern matching extension
00535     //---------------------------
00536     
00537     } else if (isBoxCase(exp, rules)) {
00538         return evalCase(rules, localValEnv);
00539 
00540     } else if (isBoxPatternVar(exp, id)) {
00541         return exp;
00542         //return evalIdDef(id, visited, localValEnv);
00543 
00544     } else if (isBoxPatternMatcher(exp)) {
00545         return exp;
00546 
00547     } else {
00548         cerr << "ERROR : EVAL don't intercept : " << *exp << endl;
00549         assert(false);
00550     }
00551 }
00552 
00553 /* Deconstruct a (BDA) op pattern (YO). */
00554 
00555 static inline bool isBoxPatternOp(Tree box, Node& n, Tree& t1, Tree& t2)
00556 {
00557     if (    isBoxPar(box, t1, t2) ||
00558             isBoxSeq(box, t1, t2) ||
00559             isBoxSplit(box, t1, t2) ||
00560             isBoxMerge(box, t1, t2) ||
00561             isBoxRec(box, t1, t2)    )
00562     {
00563         n = box->node();
00564         return true;
00565     } else {
00566         return false;
00567     }
00568 }
00569 
00570 
00571 Tree NUMERICPROPERTY = tree(symbol("NUMERICPROPERTY"));
00572 
00573 void setNumericProperty(Tree t, Tree num)
00574 {
00575     setProperty(t, NUMERICPROPERTY, num);
00576 }
00577 
00578 bool getNumericProperty(Tree t, Tree& num)
00579 {
00580     return getProperty(t, NUMERICPROPERTY, num);
00581 }
00582 
00589 /* uncomment for debugging output */
00590 //#define DEBUG
00591 Tree simplifyPattern (Tree value)
00592 {
00593     Tree num;
00594     if (!getNumericProperty(value,num)) {
00595         if (!isBoxNumeric(value,num)) {
00596             num = value;
00597         }
00598         setNumericProperty(value,num);
00599     }
00600     return num;
00601 }
00602 
00603 
00604 static bool isBoxNumeric (Tree in, Tree& out)
00605 {
00606     int     numInputs, numOutputs;
00607     double  x;
00608     int     i;
00609     Tree    v;
00610 
00611     if (isBoxInt(in, &i) || isBoxReal(in, &x)) {
00612         out = in;
00613         return true;
00614     } else {
00615         v = a2sb(in);
00616         if ( getBoxType(v, &numInputs, &numOutputs) && (numInputs == 0) && (numOutputs == 1) ) {
00617             // potential numerical expression
00618             Tree lsignals = boxPropagateSig(nil, v , makeSigInputList(numInputs) );
00619             Tree res = simplify(hd(lsignals));
00620             if (isSigReal(res, &x))     {
00621             out = boxReal(x);
00622             return true;
00623             }
00624             if (isSigInt(res, &i))      {
00625             out = boxInt(i);
00626             return true;
00627             }
00628         }
00629         return false;
00630     }
00631 }
00632 
00633 static Tree patternSimplification (Tree pattern)
00634 {   
00635     
00636     Node    n(0);
00637     Tree    v, t1, t2;
00638     
00639     if (isBoxNumeric(pattern, v)) {
00640         return v;
00641     } else if (isBoxPatternOp(pattern, n, t1, t2)) {
00642         return tree(n, patternSimplification(t1), patternSimplification(t2));
00643     } else {
00644         return pattern;
00645     }
00646 }
00647 
00648 
00649 
00663 static double eval2double (Tree exp, Tree visited, Tree localValEnv)
00664 {
00665     Tree diagram = a2sb(eval(exp, visited, localValEnv)); // pour getBoxType
00666     int numInputs, numOutputs;
00667     getBoxType(diagram, &numInputs, &numOutputs);
00668     if ( (numInputs > 0) || (numOutputs != 1) ) {
00669         evalerror (yyfilename, yylineno, "not a constant expression of type : (0->1)", exp);
00670         return 1;
00671     } else {
00672         Tree lsignals = boxPropagateSig(nil, diagram , makeSigInputList(numInputs) );
00673         Tree val = simplify(hd(lsignals));
00674         return tree2float(val);
00675     }
00676 }
00677 
00678 
00692 static int eval2int (Tree exp, Tree visited, Tree localValEnv)
00693 {
00694     Tree diagram = a2sb(eval(exp, visited, localValEnv));   // pour getBoxType()
00695     int numInputs, numOutputs;
00696     getBoxType(diagram, &numInputs, &numOutputs);
00697     if ( (numInputs > 0) || (numOutputs != 1) ) {
00698         evalerror (yyfilename, yylineno, "not a constant expression of type : (0->1)", exp);
00699         return 1;
00700     } else {
00701         Tree lsignals = boxPropagateSig(nil, diagram , makeSigInputList(numInputs) );
00702         Tree val = simplify(hd(lsignals));
00703         return tree2int(val);
00704     }
00705 }
00706 
00707 static bool isDigitChar(char c)
00708 {
00709     return (c >= '0') & (c <= '9');
00710 }
00711 
00712 static bool isIdentChar(char c)
00713 {
00714     return ((c >= 'a') & (c <= 'z')) || ((c >= 'A') & (c <= 'Z')) || ((c >= '0') & (c <= '9')) || (c == '_');
00715 }
00716 
00717 const char* Formats [] = {"%d", "%1d", "%2d", "%3d", "%4d"};
00718 
00719 static char* writeIdentValue(char* dst, int format, const char* ident, Tree visited, Tree localValEnv)
00720 {
00721     int n = eval2int(boxIdent(ident), visited, localValEnv);
00722     int i = min(4,max(format,0));
00723     
00724     return dst + sprintf(dst, Formats[i], n);
00725 }
00726 
00727 static const char * evalLabel (const char* label, Tree visited, Tree localValEnv)
00728 {
00729     char        res[2000];
00730     char        ident[64];
00731 
00732     const char* src = &label[0];
00733     char*       dst = &res[0];
00734     char*       id  = &ident[0];
00735 
00736     bool        parametric = false;
00737     int         state = 0; int format = 0;
00738     char        c;
00739 
00740     while ((c=*src++)) {
00741         if (state == 0) {
00742             // outside ident mode
00743             if (c == '%') {
00744                 // look ahead for next char
00745                 if (*src == '%') {
00746                     *dst++ = *src++;        // copy escape char and skip one char
00747                 } else {
00748                     state = 1;              // prepare ident mode
00749                     format = 0;
00750                     parametric = true;
00751                     id  = &ident[0];
00752                 }
00753             } else {
00754                 *dst++ = c;                 // copy char
00755             }
00756         } else if (state == 1) {
00757             // read the format 
00758             if (isDigitChar(c)) {
00759                 format = format*10 + (c-'0');
00760             } else {
00761                 state = 2;
00762                 --src; // unread !!!
00763             }
00764 
00765         } else {
00766             
00767             // within ident mode
00768             if (isIdentChar(c)) {
00769                 *id++ = c;
00770             } else {
00771                 *id = 0;
00772                 dst = writeIdentValue(dst, format, ident, visited, localValEnv);
00773                 state = 0;
00774                 src -= 1;
00775             }
00776         }
00777     }
00778 
00779     if (state == 2) {
00780         *id = 0;
00781         dst = writeIdentValue(dst, format, ident, visited, localValEnv);
00782     }
00783     *dst = 0;
00784     return (parametric) ? strdup(res) : label;
00785 }
00786 
00787 
00788 
00802 static Tree iteratePar (Tree id, int num, Tree body, Tree visited, Tree localValEnv)
00803 {
00804     assert (num>0);
00805 
00806     Tree res = eval(body, visited, pushValueDef(id, tree(num-1), localValEnv));
00807     for (int i = num-2; i >= 0; i--) {
00808         res = boxPar(eval(body, visited, pushValueDef(id, tree(i), localValEnv)), res);
00809     }
00810 
00811     return res;
00812 }
00813 
00814 
00815 
00828 static Tree iterateSeq (Tree id, int num, Tree body, Tree visited, Tree localValEnv)
00829 {
00830     assert (num>0);
00831 
00832     Tree res = eval(body, visited, pushValueDef(id, tree(num-1), localValEnv));
00833     for (int i = num-2; i >= 0; i--) {
00834         res = boxSeq(eval(body, visited, pushValueDef(id, tree(i), localValEnv)), res);
00835     }
00836 
00837     return res;
00838 }
00839 
00840 
00841 
00855 static Tree iterateSum (Tree id, int num, Tree body, Tree visited, Tree localValEnv)
00856 {
00857     assert (num>0);
00858 
00859     Tree res = eval(body, visited, pushValueDef(id, tree(0), localValEnv));
00860 
00861     for (int i = 1; i < num; i++) {
00862         res = boxSeq(boxPar(res, eval(body, visited, pushValueDef(id, tree(i), localValEnv))),boxPrim2(sigAdd)) ;
00863     }
00864 
00865     return res;
00866 }
00867 
00868 
00869 
00883 static Tree iterateProd (Tree id, int num, Tree body, Tree visited, Tree localValEnv)
00884 {
00885     assert (num>0);
00886 
00887     Tree res = eval(body, visited, pushValueDef(id, tree(0), localValEnv));
00888 
00889     for (int i = 1; i < num; i++) {
00890         res = boxSeq(boxPar(res, eval(body, visited, pushValueDef(id, tree(i), localValEnv))),boxPrim2(sigMul)) ;
00891     }
00892 
00893     return res;
00894 }
00895 
00904  #if 1
00905 static bool boxlistOutputs(Tree boxlist, int* outputs)
00906 {
00907     int ins, outs;
00908 
00909     *outputs = 0;
00910     while (!isNil(boxlist))
00911     {
00912         Tree b = a2sb(hd(boxlist)); // for getBoxType, suppose list of evaluated boxes
00913         if (getBoxType(b, &ins, &outs)) {
00914             *outputs += outs;
00915         } else {
00916             // arbitrary output arity set to 1
00917             // when can't be determined
00918             *outputs += 1;
00919         }
00920         boxlist = tl(boxlist);
00921     }
00922     return isNil(boxlist);
00923 }
00924 #else
00925 static bool boxlistOutputs(Tree boxlist, int* outputs)
00926 {
00927     int ins, outs;
00928 
00929     *outputs = 0;
00930     while (!isNil(boxlist) && getBoxType(hd(boxlist), &ins, &outs)) {
00931             *outputs += outs;
00932             boxlist = tl(boxlist);
00933     }
00934     return isNil(boxlist);
00935 }
00936 #endif
00937 
00941 static Tree nwires(int n)
00942 {
00943     Tree l = nil;
00944     while (n--) { l = cons(boxWire(), l); }
00945     return l;
00946 }
00947 
00948 
00960 static Tree applyList (Tree fun, Tree larg)
00961 {
00962     Tree abstr;
00963     Tree globalDefEnv;
00964     Tree visited;
00965     Tree localValEnv;
00966     Tree envList;
00967     Tree originalRules;
00968     Tree revParamList;
00969 
00970     Tree id;
00971     Tree body;
00972     
00973     Automaton*  automat;
00974     int         state;
00975 
00976     prim2   p2;
00977 
00978     //cerr << "applyList (" << *fun << ", " << *larg << ")" << endl;
00979 
00980     if (isNil(larg)) return fun;
00981 
00982     if (isBoxError(fun) || isBoxError(larg)) {
00983         return boxError();
00984     }
00985 
00986     if (isBoxPatternMatcher(fun, automat, state, envList, originalRules, revParamList)) {
00987         Tree            result;
00988         int             state2;
00989         vector<Tree>    envVect;
00990         
00991         list2vec(envList, envVect);
00992         //cerr << "applyList/apply_pattern_matcher(" << automat << "," << state << "," << *hd(larg) << ")" << endl;
00993         state2 = apply_pattern_matcher(automat, state, hd(larg), result, envVect);
00994         //cerr << "state2 = " << state2 << "; result = " << *result << endl;
00995         if (state2 >= 0 && isNil(result)) {
00996             // we need to continue the pattern matching
00997             return applyList(
00998                         boxPatternMatcher(automat, state2, vec2list(envVect), originalRules, cons(hd(larg),revParamList)),
00999                         tl(larg) );
01000         } else if (state2 < 0) {
01001             cerr << "ERROR : pattern matching failed, no rule of " << boxpp(boxCase(originalRules)) 
01002                  << " matches argument list " << boxpp(reverse(cons(hd(larg), revParamList))) << endl;
01003             exit(1);
01004         } else {
01005             // Pattern Matching was succesful
01006             // the result is a closure that we need to evaluate.
01007             if (isClosure(result, body, globalDefEnv, visited, localValEnv)) {
01008                 // why ??? return simplifyPattern(eval(body, nil, localValEnv));
01009                 //return eval(body, nil, localValEnv);
01010                 return applyList(eval(body, nil, localValEnv), tl(larg));
01011             } else {
01012                 cerr << "wrong result from pattern matching (not a closure) : " << boxpp(result) << endl;
01013                 return boxError();
01014             }
01015         }           
01016     }
01017     if (!isClosure(fun, abstr, globalDefEnv, visited, localValEnv)) {
01018         // principle : f(a,b,c,...) ==> (a,b,c,...):f
01019          int ins, outs;
01020          
01021          // check arity of function
01022          Tree efun = a2sb(fun);
01023          //cerr << "TRACEPOINT 1 : " << boxpp(efun) << endl;
01024          if (!getBoxType(efun, &ins, &outs)) { // on laisse comme ca pour le moment
01025             // we can't determine the input arity of the expression
01026             // hope for the best
01027             return boxSeq(larg2par(larg), fun);
01028          }
01029  
01030          // check arity of arg list
01031          if (!boxlistOutputs(larg,&outs)) {
01032             // we don't know yet the output arity of larg. Therefore we can't
01033             // do any arity checking nor add _ to reach the required number of arguments
01034             // cerr << "warning : can't infere the type of : " << boxpp(larg) << endl;
01035             return boxSeq(larg2par(larg), fun);
01036          }
01037         
01038         if (outs > ins) {
01039             cerr << "too much arguments : " << outs << ", instead of : " << ins << endl;
01040             cerr << "when applying : " << boxpp(fun) << endl
01041                  << "           to : " << boxpp(larg) << endl;
01042             assert(false);
01043         }
01044         
01045         if (    (outs == 1)
01046             &&
01047                 (  ( isBoxPrim2(fun, &p2) && (p2 != sigPrefix) )
01048                 || ( getUserData(fun) && ((xtended*)getUserData(fun))->isSpecialInfix() ) ) ) {
01049             // special case : /(3) ==> _,3 : /
01050             Tree larg2 = concat(nwires(ins-outs), larg);
01051             return boxSeq(larg2par(larg2), fun);
01052 
01053         } else {
01054 
01055             Tree larg2 = concat(larg, nwires(ins-outs));
01056             return boxSeq(larg2par(larg2), fun);
01057         }
01058     }
01059 
01060     if (isBoxEnvironment(abstr)) {
01061         evalerrorbox(yyfilename, -1, "an environment can't be used as a function", fun);
01062         exit(1);
01063     }
01064 
01065     if (!isBoxAbstr(abstr, id, body)) {
01066         evalerror(yyfilename, -1, "(internal) not an abstraction inside closure", fun);
01067         exit(1);
01068     }
01069 
01070     // try to synthetise a  name from the function name and the argument name
01071     {
01072         Tree arg = eval(hd(larg), visited, localValEnv);
01073         Tree narg; if ( isBoxNumeric(arg,narg) ) { arg =  narg; } 
01074         Tree f = eval(body, visited, pushValueDef(id, arg, localValEnv));
01075 
01076         Tree    fname;
01077         if (getDefNameProperty(fun, fname)) {
01078             stringstream s; s << tree2str(fname); if (!gSimpleNames) s << "(" << boxpp(arg) << ")";
01079             setDefNameProperty(f, s.str());
01080         }
01081         return applyList(f, tl(larg));
01082     }
01083 }
01084 
01085 
01086 
01098 static Tree revEvalList (Tree lexp, Tree visited, Tree localValEnv)
01099 {
01100     Tree result = nil;
01101     //Tree lexp_orig = lexp;
01102     //cerr << "ENTER revEvalList(" << *lexp_orig << ", env:" << *localValEnv << ")" << endl;
01103     while (!isNil(lexp)) {
01104         result = cons(eval(hd(lexp), visited, localValEnv), result);
01105         lexp = tl(lexp);
01106     }
01107 
01108     //cerr << "EXIT revEvalList(" << *lexp_orig << ", env:" << *localValEnv << ") -> " << *result << endl;
01109     return result;
01110 }
01111 
01112 
01113 
01120 static Tree larg2par (Tree larg)
01121 {
01122     if (isNil(larg)) {
01123         evalerror(yyfilename, -1, "empty list of arguments", larg);
01124         exit(1);
01125     }
01126     if (isNil(tl(larg))) {
01127         return hd(larg);
01128     }
01129     return boxPar(hd(larg), larg2par(tl(larg)));
01130 }
01131 
01132 
01133 
01134 
01145 static Tree evalIdDef(Tree id, Tree visited, Tree lenv)
01146 {
01147     Tree def, name;
01148 
01149     // search the environment env for a definition of symbol id
01150     while (!isNil(lenv) && !getProperty(lenv, id, def)) {
01151         lenv = lenv->branch(0);
01152     }
01153 
01154     // check that the definition exists
01155     if (isNil(lenv)) {
01156         cerr << "undefined symbol " << *id << endl;
01157         evalerror(getDefFileProp(id), getDefLineProp(id), "undefined symbol ", id);
01158         exit(1);
01159     }
01160 
01161     //cerr << "Id definition is " << *def << endl;
01162     // check that it is not a recursive definition
01163     Tree p = cons(id,lenv);
01164     // set the definition name property
01165     if (!getDefNameProperty(def, name)) {
01166         // if the definition has no name use the identifier
01167         stringstream s; s << boxpp(id);
01168         //XXXXXX setDefNameProperty(def, s.str());
01169     }
01170 
01171     // return the evaluated definition
01172     return eval(def, addElement(p,visited), nil);
01173 }
01174 
01175 
01183 static Tree listn (int n, Tree e)
01184 {
01185     return (n<= 0) ? nil : cons(e, listn(n-1,e));
01186 }
01187 
01193 static Node PMPROPERTYNODE(symbol("PMPROPERTY"));
01194 
01195 static void setPMProperty(Tree t, Tree env, Tree pm)
01196 {
01197     setProperty(t, tree(PMPROPERTYNODE, env), pm);
01198 }
01199 
01200 static bool getPMProperty(Tree t, Tree env, Tree& pm)
01201 {
01202     return getProperty(t, tree(PMPROPERTYNODE, env), pm);
01203 }
01204 
01214 static Tree evalCase(Tree rules, Tree env)
01215 {
01216     Tree pm;
01217     if (!getPMProperty(rules, env, pm)) {
01218         Automaton*  a = make_pattern_matcher(evalRuleList(rules, env));
01219         pm = boxPatternMatcher(a, 0, listn(len(rules), pushEnvBarrier(env)), rules, nil);
01220         setPMProperty(rules, env, pm);
01221     }
01222     return pm;
01223 }       
01224 
01225 
01229 static Tree evalRuleList(Tree rules, Tree env)
01230 {
01231     //cerr << "evalRuleList "<< *rules << " in " << *env << endl;
01232     if (isNil(rules)) return nil;
01233     else return cons(evalRule(hd(rules), env), evalRuleList(tl(rules), env));
01234 }
01235 
01236 
01240 static Tree evalRule(Tree rule, Tree env)
01241 {
01242     //cerr << "evalRule "<< *rule << " in " << *env << endl;
01243     return cons(evalPatternList(left(rule), env), right(rule));
01244 }
01245 
01246 
01250 static Tree evalPatternList(Tree patterns, Tree env)
01251 {
01252     if (isNil(patterns)) {
01253         return nil;
01254     } else {
01255         return cons(    evalPattern(hd(patterns), env), 
01256                         evalPatternList(tl(patterns), env)  );
01257     }
01258 }
01259 
01260 
01265 static Tree evalPattern(Tree pattern, Tree env)
01266 {
01267     Tree p = eval(pattern, nil, env);
01268     return patternSimplification(p);
01269 }
01270 
01271 
01272 static void list2vec(Tree l, vector<Tree>& v)
01273 {
01274     while (!isNil(l)) {
01275         v.push_back(hd(l));
01276         l = tl(l);
01277     }
01278 }
01279 
01280 
01281 static Tree vec2list(const vector<Tree>& v)
01282 {
01283     Tree l = nil;
01284     int  n = v.size();
01285     while (n--) { l = cons(v[n],l); }
01286     return l;
01287 }
01288 
01289 
01290 
01291 
01293 // further simplification : replace bloc-diagrams that denote constant number by this number
01295 
01296 static property<Tree> SimplifiedBoxProperty;
01297 static Tree numericBoxSimplification(Tree box);
01298 static Tree insideBoxSimplification (Tree box);
01299 
01304 Tree boxSimplification (Tree box)
01305 {
01306     Tree    simplified;
01307 
01308     if (SimplifiedBoxProperty.get(box,simplified)) {
01309 
01310         return simplified;
01311 
01312     } else {
01313 
01314         simplified = numericBoxSimplification(box);
01315 
01316         // transferts name property if any
01317         Tree name; if (getDefNameProperty(box, name)) setDefNameProperty(simplified, name);
01318 
01319         // attach simplified expression as a property of original box
01320         SimplifiedBoxProperty.set(box,simplified);
01321 
01322         return simplified;
01323     }
01324 }
01325 
01329 Tree numericBoxSimplification(Tree box)
01330 {
01331     int     ins, outs;
01332     Tree    result;
01333     int     i;
01334     double  x;
01335 
01336     if ( ! getBoxType(box, &ins, &outs)) {
01337         cout << "ERROR in file " << __FILE__ << ':' << __LINE__ << ", Can't compute the box type of : " << *box << endl;
01338         exit(1);
01339     }
01340 
01341     if (ins==0 && outs==1) {
01342         // this box can potentially denote a number
01343         if (isBoxInt(box, &i) || isBoxReal(box, &x)) {
01344            result = box;
01345         } else {
01346             // propagate signals to discover if it simplifies to a number
01347             int     i;
01348             double  x;
01349             Tree    lsignals = boxPropagateSig(nil, box , makeSigInputList(0));
01350             Tree    s = simplify(hd(lsignals));
01351 
01352             if (isSigReal(s, &x))   {
01353                 result = boxReal(x);
01354             } else if (isSigInt(s, &i))     {
01355                 result = boxInt(i);
01356             } else {
01357                 result = insideBoxSimplification(box);
01358             }
01359         }
01360     } else {
01361         // this box can't denote a number
01362         result = insideBoxSimplification(box);
01363     }
01364     return result;
01365 }
01366 
01370 Tree insideBoxSimplification (Tree box)
01371 {
01372     int     i;
01373     double  r;
01374     prim0   p0;
01375     prim1   p1;
01376     prim2   p2;
01377     prim3   p3;
01378     prim4   p4;
01379     prim5   p5;
01380 
01381     Tree    t1, t2, ff, label, cur, min, max, step, type, name, file, slot, body;
01382 
01383 
01384     xtended* xt = (xtended*)getUserData(box);
01385 
01386     // Extended Primitives
01387 
01388     if (xt) {
01389         return box;
01390     }
01391 
01392     // Numbers and Constants
01393 
01394     else if (isBoxInt(box, &i))     {
01395         return box;
01396     }
01397     else if (isBoxReal(box, &r))    {
01398         return box;
01399     }
01400 
01401     else if (isBoxFConst(box, type, name, file))    {
01402         return box;
01403     }
01404 
01405     else if (isBoxFVar(box, type, name, file))    {
01406         return box;
01407     }
01408 
01409     // Wire and Cut
01410 
01411     else if (isBoxCut(box))                 {
01412         return box;
01413     }
01414 
01415     else if (isBoxWire(box))                {
01416         return box;
01417     }
01418 
01419     // Primitives
01420 
01421     else if (isBoxPrim0(box, &p0))          {
01422         return box;
01423     }
01424 
01425     else if (isBoxPrim1(box, &p1))          {
01426         return box;
01427     }
01428 
01429     else if (isBoxPrim2(box, &p2))              {
01430         return box;
01431     }
01432 
01433     else if (isBoxPrim3(box, &p3))              {
01434         return box;
01435     }
01436 
01437     else if (isBoxPrim4(box, &p4))              {
01438         return box;
01439     }
01440 
01441     else if (isBoxPrim5(box, &p5))              {
01442         return box;
01443     }
01444 
01445     else if (isBoxFFun(box, ff))                {
01446         return box;
01447     }
01448 
01449     // User Interface Widgets
01450 
01451     else if (isBoxButton(box, label))   {
01452         return box;
01453     }
01454 
01455     else if (isBoxCheckbox(box, label))     {
01456         return box;
01457     }
01458 
01459     else if (isBoxVSlider(box, label, cur, min, max, step))     {
01460         return box;
01461     }
01462 
01463     else if (isBoxHSlider(box, label, cur, min, max, step))     {
01464         return box;
01465     }
01466 
01467     else if (isBoxNumEntry(box, label, cur, min, max, step))    {
01468         return box;
01469     }
01470 
01471     else if (isBoxVBargraph(box, label, min, max))  {
01472         return box;
01473     }
01474 
01475     else if (isBoxHBargraph(box, label, min, max))  {
01476         return box;
01477     }
01478 
01479     // User Interface Groups
01480 
01481     else if (isBoxVGroup(box, label, t1))   {
01482         return boxVGroup(label, boxSimplification(t1));
01483     }
01484 
01485     else if (isBoxHGroup(box, label, t1))   {
01486         return boxHGroup(label, boxSimplification(t1));
01487     }
01488 
01489     else if (isBoxTGroup(box, label, t1))   {
01490         return boxTGroup(label, boxSimplification(t1));
01491     }
01492 
01493     // Slots and Symbolic Boxes
01494 
01495     else if (isBoxSlot(box))                {
01496         return box;;
01497     }
01498 
01499     else if (isBoxSymbolic(box, slot, body)){
01500 
01501         Tree b = boxSimplification(body);
01502         return boxSymbolic(slot,b);
01503     }
01504 
01505     // Block Diagram Composition Algebra
01506 
01507     else if (isBoxSeq(box, t1, t2))     {
01508         Tree s1 = boxSimplification(t1);
01509         Tree s2 = boxSimplification(t2);
01510         return boxSeq(s1,s2);
01511     }
01512 
01513     else if (isBoxPar(box, t1, t2))     {
01514         Tree s1 = boxSimplification(t1);
01515         Tree s2 = boxSimplification(t2);
01516         return boxPar(s1,s2);
01517     }
01518 
01519     else if (isBoxSplit(box, t1, t2))   {
01520         Tree s1 = boxSimplification(t1);
01521         Tree s2 = boxSimplification(t2);
01522         return boxSplit(s1,s2);
01523     }
01524 
01525     else if (isBoxMerge(box, t1, t2))   {
01526         Tree s1 = boxSimplification(t1);
01527         Tree s2 = boxSimplification(t2);
01528         return boxMerge(s1,s2);
01529     }
01530     else if (isBoxRec(box, t1, t2))     {
01531         Tree s1 = boxSimplification(t1);
01532         Tree s2 = boxSimplification(t2);
01533         return boxRec(s1,s2);
01534     }
01535 
01536     cout << "ERROR in file " << __FILE__ << ':' << __LINE__ << ", unrecognised box expression : " << *box << endl;
01537     exit(1);
01538     return 0;
01539 }